From 8b1c4cbbaf0252ed68f62b0613a8da9725141262 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Wed, 30 Nov 2016 19:44:07 -0500 Subject: [PATCH 1/2] Add std::os::windows::process::CommandExt, with set_creation_flags and add_creation_flags methods. Fixes #37827 This adds a CommandExt trait for Windows along with an implementation of it for std::process::Command with methods to set the process creation flags that are passed to CreateProcess. --- src/libstd/process.rs | 57 +++++++++++++++++++++++++++ src/libstd/sys/windows/ext/process.rs | 31 ++++++++++++++- src/libstd/sys/windows/process.rs | 10 ++++- 3 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index c99fda9febc..912cc122e92 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1159,4 +1159,61 @@ mod tests { Ok(_) => panic!(), } } + + /// Test that process creation flags work by debugging a process. + /// Other creation flags make it hard or impossible to detect + /// behavioral changes in the process. + #[test] + #[cfg(windows)] + fn test_creation_flags() { + use os::windows::process::CommandExt; + use sys::c::{BOOL, DWORD, INFINITE}; + #[repr(C, packed)] + struct DEBUG_EVENT { + pub event_code: DWORD, + pub process_id: DWORD, + pub thread_id: DWORD, + // This is a union in the real struct, but we don't + // need this data for the purposes of this test. + pub _junk: [u8; 164], + } + + extern "system" { + fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; + fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD, dwContinueStatus: DWORD) -> BOOL; + } + + const DEBUG_PROCESS: DWORD = 1; + const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; + const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; + + let mut child = Command::new("cmd") + .add_creation_flags(DEBUG_PROCESS) + .stdin(Stdio::piped()).spawn().unwrap(); + child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); + let mut events = 0; + let mut event = DEBUG_EVENT { + event_code: 0, + process_id: 0, + thread_id: 0, + _junk: [0; 164], + }; + loop { + if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 { + panic!("WaitForDebugEvent failed!"); + } + events += 1; + + if event.event_code == EXIT_PROCESS_DEBUG_EVENT { + break; + } + + if unsafe { ContinueDebugEvent(event.process_id, + event.thread_id, + DBG_EXCEPTION_NOT_HANDLED) } == 0 { + panic!("ContinueDebugEvent failed!"); + } + } + assert!(events > 0); + } } diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index bce32959a23..f5bf3354637 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -15,7 +15,7 @@ use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle, IntoRawHandle}; use process; use sys; -use sys_common::{AsInner, FromInner, IntoInner}; +use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { @@ -97,3 +97,32 @@ impl ExitStatusExt for process::ExitStatus { process::ExitStatus::from_inner(From::from(raw)) } } + +/// Windows-specific extensions to the `std::process::Command` builder +#[unstable(feature = "windows_process_extensions", issue = "37827")] +pub trait CommandExt { + /// Sets the [process creation flags][1] to be passed to `CreateProcess`. + /// + /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. + /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx + #[unstable(feature = "windows_process_extensions", issue = "37827")] + fn set_creation_flags(&mut self, flags: u32) -> &mut process::Command; + /// Add `flags` to the the [process creation flags][1] to be passed to `CreateProcess`. + /// + /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. + /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx + #[unstable(feature = "windows_process_extensions", issue = "37827")] + fn add_creation_flags(&mut self, flags: u32) -> &mut process::Command; +} + +#[unstable(feature = "windows_process_extensions", issue = "37827")] +impl CommandExt for process::Command { + fn set_creation_flags(&mut self, flags: u32) -> &mut process::Command { + self.as_inner_mut().set_creation_flags(flags); + self + } + fn add_creation_flags(&mut self, flags: u32) -> &mut process::Command { + self.as_inner_mut().add_creation_flags(flags); + self + } +} diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index d371714ff0e..a221c67efd9 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -54,6 +54,7 @@ pub struct Command { args: Vec, env: Option>, cwd: Option, + flags: u32, detach: bool, // not currently exposed in std::process stdin: Option, stdout: Option, @@ -84,6 +85,7 @@ impl Command { args: Vec::new(), env: None, cwd: None, + flags: 0, detach: false, stdin: None, stdout: None, @@ -124,6 +126,12 @@ impl Command { pub fn stderr(&mut self, stderr: Stdio) { self.stderr = Some(stderr); } + pub fn set_creation_flags(&mut self, flags: u32) { + self.flags = flags; + } + pub fn add_creation_flags(&mut self, flags: u32) { + self.flags = self.flags | flags; + } pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) -> io::Result<(Process, StdioPipes)> { @@ -157,7 +165,7 @@ impl Command { cmd_str.push(0); // add null terminator // stolen from the libuv code. - let mut flags = c::CREATE_UNICODE_ENVIRONMENT; + let mut flags = self.flags | c::CREATE_UNICODE_ENVIRONMENT; if self.detach { flags |= c::DETACHED_PROCESS | c::CREATE_NEW_PROCESS_GROUP; } From e6975e974841c59a6e67e8a158b306f29d35d513 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Wed, 30 Nov 2016 21:31:47 -0500 Subject: [PATCH 2/2] just add one method named creation_flags, fix the tidy error --- src/libstd/process.rs | 5 +++-- src/libstd/sys/windows/ext/process.rs | 16 +++------------- src/libstd/sys/windows/process.rs | 5 +---- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 912cc122e92..f41fbcc66b4 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1180,7 +1180,8 @@ mod tests { extern "system" { fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; - fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD, dwContinueStatus: DWORD) -> BOOL; + fn ContinueDebugEvent(dwProcessId: DWORD, dwThreadId: DWORD, + dwContinueStatus: DWORD) -> BOOL; } const DEBUG_PROCESS: DWORD = 1; @@ -1188,7 +1189,7 @@ mod tests { const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; let mut child = Command::new("cmd") - .add_creation_flags(DEBUG_PROCESS) + .creation_flags(DEBUG_PROCESS) .stdin(Stdio::piped()).spawn().unwrap(); child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); let mut events = 0; diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index f5bf3354637..0a3221aeae6 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -106,23 +106,13 @@ pub trait CommandExt { /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx #[unstable(feature = "windows_process_extensions", issue = "37827")] - fn set_creation_flags(&mut self, flags: u32) -> &mut process::Command; - /// Add `flags` to the the [process creation flags][1] to be passed to `CreateProcess`. - /// - /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. - /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx - #[unstable(feature = "windows_process_extensions", issue = "37827")] - fn add_creation_flags(&mut self, flags: u32) -> &mut process::Command; + fn creation_flags(&mut self, flags: u32) -> &mut process::Command; } #[unstable(feature = "windows_process_extensions", issue = "37827")] impl CommandExt for process::Command { - fn set_creation_flags(&mut self, flags: u32) -> &mut process::Command { - self.as_inner_mut().set_creation_flags(flags); - self - } - fn add_creation_flags(&mut self, flags: u32) -> &mut process::Command { - self.as_inner_mut().add_creation_flags(flags); + fn creation_flags(&mut self, flags: u32) -> &mut process::Command { + self.as_inner_mut().creation_flags(flags); self } } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index a221c67efd9..969de6b85a6 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -126,12 +126,9 @@ impl Command { pub fn stderr(&mut self, stderr: Stdio) { self.stderr = Some(stderr); } - pub fn set_creation_flags(&mut self, flags: u32) { + pub fn creation_flags(&mut self, flags: u32) { self.flags = flags; } - pub fn add_creation_flags(&mut self, flags: u32) { - self.flags = self.flags | flags; - } pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) -> io::Result<(Process, StdioPipes)> {