Description
Observing an environment variable concurrently with a call to setenv
constitutes a data race. Rust currently handles this by using a mutex, but that only protects against functions in std::env
. My interpretation of POSIX (which appears to be the same as the glibc developers') is that any libc function is allowed to call getenv
. This has already caused problems with getaddrinfo
in #27970.
Additionally, a large amount of C code calls getenv
but is otherwise thread-safe. While this isn't necessarily the standard library's issue, it's impossible for third-party libraries to soundly use this code without requiring the user to certify that this isn't an issue via an unsafe
block. Some examples of this happening in practice are in time-rs/time#293 and rust-lang/flate2-rs#272.
rustsec/advisory-db#926 had several proposals on how this could be handled brought up.
Make std::env::set_var
unsafe
This is arguably the cleanest solution to the issue. This could be considered a soundness fix, which would make it an option, but the ecosystem impact feels like it'd be too big.
Don't actually call setenv
std
could keep track of the environment itself, and make set_var
changes only visible to var
and subprocesses. This is probably the way to solve the issue with the least impact on existing code, but the behavior is somewhat unexpected and not zero-cost.
Only call setenv
in single-threaded code
This would reduce the impact further, but seems even less expected for negligible benefit.
Deprecate std::env::set_var
This would make it clear that setting an environment variable in the current process is discouraged. It could also be combined with not actually calling setenv
, which would be my preferred solution to this issue.
Activity
localtime_r
may be unsound chronotope/chrono#499vi commentedon Oct 29, 2021
Shall it be made
unsafe fn
, just likestd::os::unix::process::CommandExt::pre_exec
?leo60228 commentedon Oct 29, 2021
The discussion in #39575 is definitely helpful here, but I don't think the same conclusions can reasonably apply to
std::env::set_var
.tarcieri commentedon Oct 29, 2021
Indeed. Notably they retroactively changed
pre_exec
tounsafe
based on a justification that there weren't real-world uses of it.That's not the case with
set_var
: https://github.com/search?l=Rust&type=Code&q=set_varI think to accomplish a similar effect,
set_var
would have to be deprecated, and a newunsafe fn
introduced in its place (which is more or less combining options 1 & 4 proposed in the OP)leo60228 commentedon Oct 29, 2021
That's what happened with
pre_exec
.before_exec
is the old name.leo60228 commentedon Nov 10, 2021
For reference, .NET takes option #2.
cgwalters commentedon Nov 11, 2021
Hi, there's a bunch of discussion on this issue, but I think https://internals.rust-lang.org/t/synchronized-ffi-access-to-posix-environment-variable-functions/15475 has the most information right now.
env::{set, remove}_var
#92365briansmith commentedon Jan 4, 2022
There is a lot of discussion in #27970 that's really about this issue. This is largely my fault because I didn't know this issue existed.
briansmith commentedon Jan 4, 2022
I looked at an application that is using
set_var
in multiple places:To provide a default value forRUST_LOG=debug
when it wasn't already set. We'd prefer a way to do this without setting the environment variable.RUST_BACKTRACE=full
regardless of what the environment says. Again, we'd prefer a way to do this without setting an environment variable.To do shell scripting, but in Rust. Not a big deal for us to use an[Edit: We can useunsafe
function for this, though not ideal.Command::{env,envs}
.]73 remaining items