summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2018-11-13 14:57:10 -0800
committerAlex Crichton <alex@alexcrichton.com>2018-11-15 05:42:16 -0800
commit9609a91e2cacea6bcd3729f91ef6f1503960ac20 (patch)
treed4e03a9d921aa297837cf51b9a9ed5188c515364 /src/test
parentf42daea4c358f8d67934981f31b44bac34e20df2 (diff)
downloadrust-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.rs36
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");
+    }
 }