-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Command/environment variable interaction is confusing and error-prone #28975
Comments
Tagging with the libs team here, I don't know if they want to make a change or not. |
I agree, the current behavior seems broken to me. Would you expect the environment to be captured when My only concern would be that if we provide getters on the Command builder as requested in #44434, the user may call a getter to get the child environment to validate, which would need to dynamically compute the environment based on the current parent process environment. let mut cmd = Command::new("...");
fill_in_the_environment(&mut cmd);
let child_env = cmd.get_the_environment();
validate_the_environment(child_env)?;
/* Environment is global state, suppose it changes in between. Now the environment
we validated is no longer the one that the process will run with. */
cmd.spawn()?; |
@dtolnay yes, personally I'd prefer capturing it during
|
I would be prepared to consider a PR that delays capturing environment variables from the parent process until |
@dtolnay I started implementing this, and found the reason for the odd behaviour: at the moment, the linux implementation provides the method // Currently we try hard to ensure that the call to `.exec()` doesn't
// actually allocate any memory. While many platforms try to ensure that
// memory allocation works after a fork in a multithreaded process, it's
// been observed to be buggy and somewhat unreliable, so we do our best to
// just not do it at all!
//
// Along those lines, the `argv` and `envp` raw pointers here are exactly
// what's gonna get passed to `execvp`. The `argv` array starts with the
// `program` and ends with a NULL, and the `envp` pointer, if present, is
// also null-terminated.
//
// Right now we don't support removing arguments, so there's no much fancy
// support there, but we support adding and removing environment variables,
// so a side table is used to track where in the `envp` array each key is
// located. Whenever we add a key we update it in place if it's already
// present, and whenever we remove a key we update the locations of all
// other keys. I don't see a way to retain this (undocumented) guarantee if environment variables are captured at the point of spawn. However, my suspicion is that the comment may be referring to |
@Diggsey I interpreted that comment to mean that no allocations should happen after When I was playing with this, I was surprised that the implementations for |
Capture `Command` environment at spawn Fixes #28975 This tracks a set of changes to the environment and then replays them at spawn time.
Capture `Command` environment at spawn Fixes #28975 This tracks a set of changes to the environment and then replays them at spawn time.
The API which Command exposes implies that environment variables are captured from the parent process at the point where it is constructed, and then may be subsequently modified through the use of
env
/env_remove
/env_clear
.However, in reality the environment variables are captured lazily, when the first environment modifier is applied to the command. There's also no way to explicitly trigger the environment capture without actually modifying the environment.
This results in unpredictable behaviour if environment variables are modified between Command construction, and Command execution. Perhaps this is done as an optimization. However, spawning a new process far outweighs the cost of copying a few strings.
Environment variables are global state: it's a bad idea for accesses to global state to happen at an unpredictable time.
Finally, regardless of whether the behaviour is changed, it should be clearly documented what the behaviour is.
The text was updated successfully, but these errors were encountered: