diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2018-11-13 14:57:10 -0800 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2018-11-15 05:42:16 -0800 |
| commit | 9609a91e2cacea6bcd3729f91ef6f1503960ac20 (patch) | |
| tree | d4e03a9d921aa297837cf51b9a9ed5188c515364 /src/test | |
| parent | f42daea4c358f8d67934981f31b44bac34e20df2 (diff) | |
| download | rust-9609a91e2cacea6bcd3729f91ef6f1503960ac20.tar.gz rust-9609a91e2cacea6bcd3729f91ef6f1503960ac20.zip | |
std: Synchronize access to global env during `exec`
This commit, after reverting #55359, applies a different fix for #46775 while also fixing #55775. The basic idea was to go back to pre-#55359 libstd, and then fix #46775 in a way that doesn't expose #55775. The issue described in #46775 boils down to two problems: * First, the global environment is reset during `exec` but, but if the `exec` call fails then the global environment was a dangling pointer into free'd memory as the block of memory was deallocated when `Command` is dropped. This is fixed in this commit by installing a `Drop` stack object which ensures that the `environ` pointer is preserved on a failing `exec`. * Second, the global environment was accessed in an unsynchronized fashion during `exec`. This was fixed by ensuring that the Rust-specific environment lock is acquired for these system-level operations. Thanks to Alex Gaynor for pioneering the solution here! Closes #55775 Co-authored-by: Alex Gaynor <alex.gaynor@gmail.com>
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/run-pass/command-exec.rs | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/src/test/run-pass/command-exec.rs b/src/test/run-pass/command-exec.rs index 46b409fb13a..f662945c0cf 100644 --- a/src/test/run-pass/command-exec.rs +++ b/src/test/run-pass/command-exec.rs @@ -48,6 +48,23 @@ fn main() { println!("passed"); } + "exec-test5" => { + env::set_var("VARIABLE", "ABC"); + Command::new("definitely-not-a-real-binary").env("VARIABLE", "XYZ").exec(); + assert_eq!(env::var("VARIABLE").unwrap(), "ABC"); + println!("passed"); + } + + "exec-test6" => { + let err = Command::new("echo").arg("passed").env_clear().exec(); + panic!("failed to spawn: {}", err); + } + + "exec-test7" => { + let err = Command::new("echo").arg("passed").env_remove("PATH").exec(); + panic!("failed to spawn: {}", err); + } + _ => panic!("unknown argument: {}", arg), } return @@ -72,4 +89,23 @@ fn main() { assert!(output.status.success()); assert!(output.stderr.is_empty()); assert_eq!(output.stdout, b"passed\n"); + + let output = Command::new(&me).arg("exec-test5").output().unwrap(); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + assert_eq!(output.stdout, b"passed\n"); + + if cfg!(target_os = "linux") { + let output = Command::new(&me).arg("exec-test6").output().unwrap(); + println!("{:?}", output); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + assert_eq!(output.stdout, b"passed\n"); + + let output = Command::new(&me).arg("exec-test7").output().unwrap(); + println!("{:?}", output); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + assert_eq!(output.stdout, b"passed\n"); + } } |
