From a938725ef715b90d0494529142ba8a3264f8e5db Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 30 Dec 2020 14:56:51 -0800 Subject: [PATCH 1/3] Don't use posix_spawn_file_actions_addchdir_np on macOS. --- .../std/src/sys/unix/process/process_unix.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 945b43678a919..ddcb404c60ebc 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -314,10 +314,20 @@ impl Command { ) -> libc::c_int } let addchdir = match self.get_cwd() { - Some(cwd) => match posix_spawn_file_actions_addchdir_np.get() { - Some(f) => Some((f, cwd)), - None => return Ok(None), - }, + Some(cwd) => { + if cfg!(target_os = "macos") { + // There is a bug in macOS where a relative executable + // path like "../myprogram" will cause `posix_spawn` to + // successfully launch the program, but erroneously return + // ENOENT when used with posix_spawn_file_actions_addchdir_np + // which was introduced in macOS 10.15. + return Ok(None); + } + match posix_spawn_file_actions_addchdir_np.get() { + Some(f) => Some((f, cwd)), + None => return Ok(None), + } + } None => None, }; From fcbcc975767b0621a43fb9c1c872e1754e30a377 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 8 Jan 2021 13:15:43 -0800 Subject: [PATCH 2/3] Add test for Command::current_dir behavior. --- src/test/ui/command/command-current-dir.rs | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/test/ui/command/command-current-dir.rs diff --git a/src/test/ui/command/command-current-dir.rs b/src/test/ui/command/command-current-dir.rs new file mode 100644 index 0000000000000..a1a72a14958d0 --- /dev/null +++ b/src/test/ui/command/command-current-dir.rs @@ -0,0 +1,43 @@ +// run-pass +// ignore-emscripten no processes +// ignore-sgx no processes + +use std::env; +use std::fs; +use std::path::Path; +use std::process::Command; + +fn main() { + // Checks the behavior of current_dir when used with a relative exe path. + let me = env::current_exe().unwrap(); + if matches!(env::args().skip(1).next().as_deref(), Some("current-dir")) { + let cwd = env::current_dir().unwrap(); + assert_eq!(cwd.file_name().unwrap(), "bar"); + std::process::exit(0); + } + let exe = me.file_name().unwrap(); + let cwd = std::env::current_dir().unwrap(); + eprintln!("cwd={:?}", cwd); + let foo = cwd.join("foo"); + let bar = cwd.join("bar"); + fs::create_dir_all(&foo).unwrap(); + fs::create_dir_all(&bar).unwrap(); + fs::copy(&me, foo.join(exe)).unwrap(); + + // Unfortunately this is inconsistent based on the platform, see + // https://github.com/rust-lang/rust/issues/37868. On Windows, + // it is relative *before* changing the directory, and on Unix + // it is *after* changing the directory. + let relative_exe = if cfg!(windows) { + Path::new("foo").join(exe) + } else { + Path::new("../foo").join(exe) + }; + + let status = Command::new(relative_exe) + .arg("current-dir") + .current_dir("bar") + .status() + .unwrap(); + assert!(status.success()); +} From 6e467b74cda020f89f1663deda5169f85d859c6d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 17 Jan 2021 14:03:23 -0800 Subject: [PATCH 3/3] Fix test to work with remote-test-server. remote-test-server does not set the current_dir, and leaves it as `/`. --- src/test/ui/command/command-current-dir.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/ui/command/command-current-dir.rs b/src/test/ui/command/command-current-dir.rs index a1a72a14958d0..91d8e4f381a36 100644 --- a/src/test/ui/command/command-current-dir.rs +++ b/src/test/ui/command/command-current-dir.rs @@ -16,8 +16,14 @@ fn main() { std::process::exit(0); } let exe = me.file_name().unwrap(); - let cwd = std::env::current_dir().unwrap(); + let cwd = me.parent().unwrap(); eprintln!("cwd={:?}", cwd); + // Change directory to where the exectuable is located, since this test + // fundamentally needs to use relative paths. In some cases (like + // remote-test-server), the current_dir can be somewhere else, so make + // sure it is something we can use. We assume we can write to this + // directory. + env::set_current_dir(&cwd).unwrap(); let foo = cwd.join("foo"); let bar = cwd.join("bar"); fs::create_dir_all(&foo).unwrap();