-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider deprecating and/or modifying behavior of std::env::set_var #90308
Comments
Shall it be made |
The discussion in #39575 is definitely helpful here, but I don't think the same conclusions can reasonably apply to |
Indeed. Notably they retroactively changed That's not the case with I think to accomplish a similar effect, |
That's what happened with |
For reference, .NET takes option #2. |
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. |
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. |
I looked at an application that is using
|
https://docs.rs/env_logger/latest/env_logger/struct.Env.html#method.filter_or
EDIT: Actually, this only affects the library backtrace, the panic runtime probably does also need a in-code setter too. |
To test functions that read from the environment. At some point we should
have a new solution for supporting this.
I don't think there's a reasonable way to support this other than running
that test in its own process. That's already prone to logic race conditions
since tests are multithreaded.
At the very least, in an integration test it should be pretty much
obviously safe to put the relevant `set_env` calls at the top of `main`.
…On Tue, Jan 4, 2022, 4:55 PM Brian Smith ***@***.***> wrote:
I looked at an application that is using set_var in multiple places:
- To provide a default value for RUST_LOG=debug when it wasn't already
set. We'd prefer a way to do this without setting the environment variable.
- To force RUST_BACKTRACE=full regardless of what the environment
says. Again, we'd prefer a way to do this without setting an environment
variable.
- To test functions that read from the environment. At some point we
should have a new solution for supporting this.
- To do shell scripting, but in Rust. Not a big deal for us to use an
unsafe function for this, though not ideal.
—
Reply to this email directly, view it on GitHub
<#90308 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB7X32OITRPXKVTYYIVWD7LUUNUGHANCNFSM5GYFKLHA>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
First, it turns out that our use of As far as testing goes, if the |
In order to use |
Miri needs something similar here, and I think we somehow have two loggers here in this process so I don't know if we can use the env_logger API as a replacement. |
And even inside such a serial test, any use of e.g. tokio or rayon could spawn threads in a not immediately obvious way. So I wouldn't bet on this approach as a good mitigation. |
@cgwalters wrote:
That's right. For the tests we have, what I suggested above would work. What we're more likely to do is refactor the code so that reading the environment is done separately from the functionality being tested, and then run the tests using a private API that allows us to pass in a fake environment stored in a |
It seems like that could be solved by just making |
I am not sure how easy that would be, but yeah something like that would probably be needed. For the other use of |
Per rust-lang/rust#90308, this is potentially a data race. In practice, I don't think it was actually problematic here, but it also wasn't doing anything of value, so we should remove it. This is currently the only `env::set_var` or `env::remove_var` call in the proxy. Closes linkerd/linkerd2#7651
Per rust-lang/rust#90308, this is potentially a data race. In practice, I don't think it was actually problematic here, but it also wasn't doing anything of value, so we should remove it. This is currently the only `env::set_var` or `env::remove_var` call in the proxy. To prevent uses of these functions in the future, I also added a `disallowed-methods` configuration in `.clippy.toml` to emit a warning for any uses of `std::env::set_var` and `std::env::remove_var`. Unfortunately, this required adding a `deny` attribute basically everywhere, which is why this diff touches so many files. Closes linkerd/linkerd2#7651
I ran into the Go version of this problem (see golang/go#63567 ). I think realistically, this is a small problem, and the solutions described in this thread seem reasonable. However, I am unreasonably annoyed that this problem with the C standard has been known for decades, and we can't get that fixed. I think ultimately we need the C standard to adopt a solution. My unrealistic idea: I wish there was a way that Rust, Go and other languages that care about this (e.g. Julia? JuliaLang/julia#34726) could share a "safe" C implementation, as a way to either route around the C standard, and encourage the C standard to evolve a solution. I'm mentioning it in case others think this is interesting, because I'm annoyed enough to spend time on this. |
@evanj there was some discussion of trying to improve the C API on IRLO: https://internals.rust-lang.org/t/thread-safe-environment-variable-mutation/17817 |
I think you are very reasonably annoyed. ;)
However, where would such a shared API go? Realistically I think we'd have to convince glibc, or else we'd all have to add a new dependency to all our programs and that's just not going to fly. Maybe if people from multiple languages make a joint effort, that increases our chances of convincing glibc... Not sure.
|
I was wondering if there was some way to implement a tiny library such that
By being statically linked, the library could be included with the Rust standard library – and any other language runtimes that wanted to participate – without adding a new user-visible dependency. By sharing state, the library copies could all have a single source of truth for the current process's "thread-safe environment". Sharing state doesn't seem that hard: on Unix, a global weak symbol would work in almost all cases. But there's at least one case where global weak symbols end up not actually being globally unique: when a dylib is linked with linker options that limit its exported symbols list. Is that a deal-breaker? Maybe not? I also don't know how this would work on Windows, which doesn't support global weak symbols. Maybe it would suffice to not invent a new source of truth there and just use the existing thread-safe …This is all probably a pipe dream though. |
It wouldn't be needed on Windows because, as you say, modifying then environment is already thread safe. |
This issue is now over 2 years old (and we've known about it a lot longer than that). It took glibc 3 years from when I would also say that I don't have much hope that there would be a |
There is a PR open (#94619) to add unsafe APIs with new names. I have no problem updating it to resolve the conflicts and whatever else may be necessary. It's currently marked as blocked on whether |
…r, r=TaKO8Ki rustc_log: provide a way to init logging based on the values, not names, of the env vars Miri wants to affect how rustc does logging. So far this required setting environment variables before calling `rustc_driver::init_rustc_env_logger`. However, `set_var` is a function one should really [avoid calling](rust-lang#90308), so this adds the necessary APIs to rustc such that Miri can just pass it the *values* of all the log-relevant environment variables, rather than having to change the global environment.
rustc_log: provide a way to init logging based on the values, not names, of the env vars Miri wants to affect how rustc does logging. So far this required setting environment variables before calling `rustc_driver::init_rustc_env_logger`. However, `set_var` is a function one should really [avoid calling](rust-lang/rust#90308), so this adds the necessary APIs to rustc such that Miri can just pass it the *values* of all the log-relevant environment variables, rather than having to change the global environment.
rustc_log: provide a way to init logging based on the values, not names, of the env vars Miri wants to affect how rustc does logging. So far this required setting environment variables before calling `rustc_driver::init_rustc_env_logger`. However, `set_var` is a function one should really [avoid calling](rust-lang/rust#90308), so this adds the necessary APIs to rustc such that Miri can just pass it the *values* of all the log-relevant environment variables, rather than having to change the global environment.
rustc_log: provide a way to init logging based on the values, not names, of the env vars Miri wants to affect how rustc does logging. So far this required setting environment variables before calling `rustc_driver::init_rustc_env_logger`. However, `set_var` is a function one should really [avoid calling](rust-lang/rust#90308), so this adds the necessary APIs to rustc such that Miri can just pass it the *values* of all the log-relevant environment variables, rather than having to change the global environment.
Allow calling these functions without `unsafe` blocks in editions up until 2021, but don't trigger the `unused_unsafe` lint for `unsafe` blocks containing these functions. Fixes rust-lang#27970. Fixes rust-lang#90308.
Allow calling these functions without `unsafe` blocks in editions up until 2021, but don't trigger the `unused_unsafe` lint for `unsafe` blocks containing these functions. Fixes rust-lang#27970. Fixes rust-lang#90308.
Make `std::env::{set_var, remove_var}` unsafe in edition 2024 Allow calling these functions without `unsafe` blocks in editions up until 2021, but don't trigger the `unused_unsafe` lint for `unsafe` blocks containing these functions. Fixes rust-lang#27970. Fixes rust-lang#90308.
Allow calling these functions without `unsafe` blocks in editions up until 2021, but don't trigger the `unused_unsafe` lint for `unsafe` blocks containing these functions. Fixes rust-lang#27970. Fixes rust-lang#90308. CC rust-lang#124866.
Allow calling these functions without `unsafe` blocks in editions up until 2021, but don't trigger the `unused_unsafe` lint for `unsafe` blocks containing these functions. Fixes rust-lang#27970. Fixes rust-lang#90308. CC rust-lang#124866.
Allow calling these functions without `unsafe` blocks in editions up until 2021, but don't trigger the `unused_unsafe` lint for `unsafe` blocks containing these functions. Fixes rust-lang#27970. Fixes rust-lang#90308. CC rust-lang#124866.
Allow calling these functions without `unsafe` blocks in editions up until 2021, but don't trigger the `unused_unsafe` lint for `unsafe` blocks containing these functions. Fixes rust-lang#27970. Fixes rust-lang#90308. CC rust-lang#124866.
Make `std::env::{set_var, remove_var}` unsafe in edition 2024 Allow calling these functions without `unsafe` blocks in editions up until 2021, but don't trigger the `unused_unsafe` lint for `unsafe` blocks containing these functions. Fixes rust-lang#27970. Fixes rust-lang#90308. CC rust-lang#124866.
Make `std::env::{set_var, remove_var}` unsafe in edition 2024 Allow calling these functions without `unsafe` blocks in editions up until 2021, but don't trigger the `unused_unsafe` lint for `unsafe` blocks containing these functions. Fixes rust-lang#27970. Fixes rust-lang#90308. CC rust-lang#124866.
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 instd::env
. My interpretation of POSIX (which appears to be the same as the glibc developers') is that any libc function is allowed to callgetenv
. This has already caused problems withgetaddrinfo
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 anunsafe
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
unsafeThis 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 makeset_var
changes only visible tovar
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 codeThis 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.The text was updated successfully, but these errors were encountered: