Skip to content

Consider deprecating and/or modifying behavior of std::env::set_var #90308

Closed
@leo60228

Description

@leo60228
Contributor

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

vi

vi commented on Oct 29, 2021

@vi
Contributor

Shall it be made unsafe fn, just like std::os::unix::process::CommandExt::pre_exec?

leo60228

leo60228 commented on Oct 29, 2021

@leo60228
ContributorAuthor

Shall it be made unsafe fn, just like std::os::unix::process::CommandExt::pre_exec?

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

tarcieri commented on Oct 29, 2021

@tarcieri
Contributor

Indeed. Notably they retroactively changed pre_exec to unsafe 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_var

I think to accomplish a similar effect, set_var would have to be deprecated, and a new unsafe fn introduced in its place (which is more or less combining options 1 & 4 proposed in the OP)

leo60228

leo60228 commented on Oct 29, 2021

@leo60228
ContributorAuthor

I think to accomplish a similar effect, set_var would have to be deprecated, and a new unsafe fn introduced in its place (which is more or less combining options 1 & 4 proposed in the OP)

That's what happened with pre_exec. before_exec is the old name.

added
T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.
on Nov 2, 2021
leo60228

leo60228 commented on Nov 10, 2021

@leo60228
ContributorAuthor

For reference, .NET takes option #2.

cgwalters

cgwalters commented on Nov 11, 2021

@cgwalters
Contributor

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.

briansmith

briansmith commented on Jan 4, 2022

@briansmith
Contributor

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.

briansmith

briansmith commented on Jan 4, 2022

@briansmith
Contributor

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. [Edit: We can use Command::{env,envs}.]

73 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-processArea: `std::process` and `std::env`C-bugCategory: This is a bug.E-help-wantedCall for participation: Help is requested to fix this issue.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @tarcieri@briansmith@comex@Nemo157@Enselic

      Issue actions

        Consider deprecating and/or modifying behavior of std::env::set_var · Issue #90308 · rust-lang/rust