diff options
author | bors <bors@rust-lang.org> | 2022-12-07 13:52:52 +0000 |
---|---|---|
committer | bors <bors@rust-lang.org> | 2022-12-07 13:52:52 +0000 |
commit | 01fbc5ae789fc0c7a2da71d3cd908451f175e4eb (patch) | |
tree | b5b7cc6674469e94e328d494e162d34fb5b49ddd | |
parent | 91b8f34ac2272e3c94a97bebc033abe8e2f17101 (diff) | |
parent | 93b774a2a47e813fd01481dab480d4be785c4427 (diff) | |
download | rust-01fbc5ae789fc0c7a2da71d3cd908451f175e4eb.tar.gz |
Auto merge of #103459 - ChrisDenton:propagate-nulls, r=thomcc
Pass on null handle values to child process
Fixes #101645
In Windows, stdio handles are (semantically speaking) `Option<Handle>` where `Handle` is a non-zero value. When spawning a process with `Stdio::Inherit`, Rust currently turns zero values into `-1` values. This has the unfortunate effect of breaking console subprocesses (which typically need stdio) that are spawned from gui applications (that lack stdio by default) because the console process won't be assigned handles from the newly created console (as they usually would in that situation). Worse, `-1` is actually [a valid handle](https://doc.rust-lang.org/std/os/windows/io/struct.OwnedHandle.html) which means "the current process". So if a console process, for example, waits on stdin and it has a `-1` value then the process will end up waiting on itself.
This PR fixes it by propagating the nulls instead of converting them to `-1`.
While I think the current behaviour is a mistake, changing it (however justified) is an API change so I think this PR should at least have some input from t-libs-api. So choosing at random...
r? `@joshtriplett`
-rw-r--r-- | library/std/src/sys/windows/process.rs | 34 |
1 files changed, 20 insertions, 14 deletions
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 9cbb4ef19e9..31e9b34fb9e 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -252,10 +252,6 @@ impl Command { ) -> io::Result<(Process, StdioPipes)> { let maybe_env = self.env.capture_if_changed(); - let mut si = zeroed_startupinfo(); - si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD; - si.dwFlags = c::STARTF_USESTDHANDLES; - let child_paths = if let Some(env) = maybe_env.as_ref() { env.get(&EnvKey::new("PATH")).map(|s| s.as_os_str()) } else { @@ -314,9 +310,21 @@ impl Command { let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?; let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, &mut pipes.stdout)?; let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?; - si.hStdInput = stdin.as_raw_handle(); - si.hStdOutput = stdout.as_raw_handle(); - si.hStdError = stderr.as_raw_handle(); + + let mut si = zeroed_startupinfo(); + si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD; + + // If at least one of stdin, stdout or stderr are set (i.e. are non null) + // then set the `hStd` fields in `STARTUPINFO`. + // Otherwise skip this and allow the OS to apply its default behaviour. + // This provides more consistent behaviour between Win7 and Win8+. + let is_set = |stdio: &Handle| !stdio.as_raw_handle().is_null(); + if is_set(&stderr) || is_set(&stdout) || is_set(&stdin) { + si.dwFlags |= c::STARTF_USESTDHANDLES; + si.hStdInput = stdin.as_raw_handle(); + si.hStdOutput = stdout.as_raw_handle(); + si.hStdError = stderr.as_raw_handle(); + } unsafe { cvt(c::CreateProcessW( @@ -513,9 +521,6 @@ fn program_exists(path: &Path) -> Option<Vec<u16>> { impl Stdio { fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> { match *self { - // If no stdio handle is available, then inherit means that it - // should still be unavailable so propagate the - // INVALID_HANDLE_VALUE. Stdio::Inherit => match stdio::get_handle(stdio_id) { Ok(io) => unsafe { let io = Handle::from_raw_handle(io); @@ -523,7 +528,8 @@ impl Stdio { io.into_raw_handle(); ret }, - Err(..) => unsafe { Ok(Handle::from_raw_handle(c::INVALID_HANDLE_VALUE)) }, + // If no stdio handle is available, then propagate the null value. + Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) }, }, Stdio::MakePipe => { @@ -730,9 +736,9 @@ fn zeroed_startupinfo() -> c::STARTUPINFO { wShowWindow: 0, cbReserved2: 0, lpReserved2: ptr::null_mut(), - hStdInput: c::INVALID_HANDLE_VALUE, - hStdOutput: c::INVALID_HANDLE_VALUE, - hStdError: c::INVALID_HANDLE_VALUE, + hStdInput: ptr::null_mut(), + hStdOutput: ptr::null_mut(), + hStdError: ptr::null_mut(), } } |