Widely used, yes. Used as in read. Why do any of these need to change at runtime? And if they do - why are they environment variables?
(NB: starting a new process is not "at runtime")
Widely used, yes. Used as in read. Why do any of these need to change at runtime? And if they do - why are they environment variables?
(NB: starting a new process is not "at runtime")
Also, few weeks ago I found a use for them when trying to pass configuration from Java/Kotlin to C++ library to be used during static constructors (invoked during dlopen) on Android, because at that phase native code cannot call back to JVM.
library has already loaded when you call setenv, so what you're saying doesn't work in most cases.
It seems to be a need to use poorly written libraries. You might consider fixing them instead.
This issue with that “interface” is the environment is process global. If the library is being loaded dynamically (specifically for some task) it would seem that the parameters are local to that task and should be taken by some reentrent init method. Alternatively, the process could be forked and environment set in the child without concern for thread safety or polluting the environment (think of the children!).
The only exception is things like debug logging, which is unlikely even to work dynamically.
On the other hand, setenv() is clearly broken in modern code, particularly in a library context, and the man page (at least on my Linux machine) does not make that particularly obvious -- "Thread safety: MT-Unsafe" is the only note, with a reference to attributes(7) for more information. It could definitely be made more obvious.
Edit: I just realized macOS/FreeBSD has execvP() that allows passing a custom search path, so PATH is now safe, but without a -e variant, everything else is again unsafe.
In a program you could have either.
Sort of. https://pubs.opengroup.org/onlinepubs/9699919799/functions/g...:
“The returned string pointer might be invalidated or the string content might be overwritten by a subsequent call to getenv()”
There’s little you can do with a broken API, so Linux has that ‘feature’, too. https://man7.org/linux/man-pages/man3/getenv.3.html:
“The string pointed to by the return value of getenv() may be statically allocated, and can be modified by a subsequent call to getenv(), putenv(3), setenv(3), or unsetenv(3).”
FreeBSD chooses to leak memory, instead. https://man.freebsd.org/cgi/man.cgi?getenv(3):
“Successive calls to setenv() that assign a larger-sized value than any previous value to the same name will result in a memory leak. The FreeBSD semantics for this function (namely, that the contents of value are copied and that old values remain accessible indefinitely) make this bug unavoidable”
So, shells use a single thread that can safely modify the environment - then start new child processes by the same thread. The child processes get a =copy= of the said environment. That's a textbook example how to use env.
Starting multiple threads on your own, then modifying env should be considered a textbook example how not to do things - env is not intended for interprocess communication.
(Edit: removed unneeded pointing out execve)
Also shells generally have their own program search anyway since they need to support built-in commands. It's not particularly hard to implement PATH search.
As for I’m not aware of execve etc… You need to re-read my comment which clearly mentions execve, execvep, posix_spawn, as well as implementing PATH search on your own.
I am the OP and your assumption is incorrect. You may consider why the post ends with:
(NB: starting a new process is not "at runtime")I mean YES you can factor your code (tests, whatever) to make this a non-issue but supposing some person wrote some code 10 years ago in an OSS project or on your team and you start banging into this issue.
It’s not going to be trivial to unwind let alone find the root issue.
Let’s start fixing things like this for our future selves, right?
Digging heels in and saying “eh, you just got to learn this one weird quirk.. oh yeah this other one too..” is kind of a fun glass bead game until it’s not; as is not a winnning way to endear hearts and minds.
Other than that, it can also be handy in k8s with a VPA. You get more/less memory and then update the env to reflect that. Your service picks up the env change and updates the runtime.
IIRC, there is/was some way to listen to those changes in C#, and automatically update runtime settings.
You… can't change the env from outside the process…
are you saying this is used by disjoint components within a single process? Or is this just a misunderstanding?
But you only need access to the /proc/pid directory to change another processes env.
/proc/$pid/environ is not writable
(and as a matter of fact, due to how the environment works, it cannot be writable.)
Not with that attitude you can't.
(OK, without the joke: you can do this with an interactive debugger. But I think OP just meant "change it in the container and then restart the child process")
Most debuggers nowadays support altering variables at runtime after hitting breakpoints. In the meantime this was the very first time I ever heard anyone even considering changing env vars at runtime, let alone use it to debug stuff. Sounds like an ass-backwards way of going about debugging.
Wait, why would this need to happen at runtime? I have used env cars a lot to trigger specific cases but why would you want to do this while the process is running from within the process itself?
If you control the process you can start it with the right env to begin with, no?
If you want to pass secrets into a process at startup, I would strongly recommend passing a pipe as an additional open file descriptor (e.g. fd #4, but this FD number you can then put in an env variable) and writing it onto the pipe. It can only be read once, and you can control where the value propagates.