about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-12-05 06:53:56 +0000
committerbors <bors@rust-lang.org>2016-12-05 06:53:56 +0000
commitb4f4b65f9934b2728e9be0c02855aba3b31ad311 (patch)
treeb016cf9e2fc2c3bd023d3d014e1966589a83ddad /src/libstd
parent6bc551a261de4b62a50761e624dc8fd27c85c4ce (diff)
parente6975e974841c59a6e67e8a158b306f29d35d513 (diff)
downloadrust-b4f4b65f9934b2728e9be0c02855aba3b31ad311.tar.gz
rust-b4f4b65f9934b2728e9be0c02855aba3b31ad311.zip
Auto merge of #38098 - luser:windows-commandext, r=alexcrichton
Add std::os::windows::process::CommandExt. 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.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/process.rs58
-rw-r--r--src/libstd/sys/windows/ext/process.rs21
-rw-r--r--src/libstd/sys/windows/process.rs7
3 files changed, 84 insertions, 2 deletions
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 9e1b57c7412..bfc36d5b21f 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -1167,4 +1167,62 @@ 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")
+            .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..0a3221aeae6 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,22 @@ 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 creation_flags(&mut self, flags: u32) -> &mut process::Command;
+}
+
+#[unstable(feature = "windows_process_extensions", issue = "37827")]
+impl CommandExt for process::Command {
+    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 d371714ff0e..969de6b85a6 100644
--- a/src/libstd/sys/windows/process.rs
+++ b/src/libstd/sys/windows/process.rs
@@ -54,6 +54,7 @@ pub struct Command {
     args: Vec<OsString>,
     env: Option<HashMap<OsString, OsString>>,
     cwd: Option<OsString>,
+    flags: u32,
     detach: bool, // not currently exposed in std::process
     stdin: Option<Stdio>,
     stdout: Option<Stdio>,
@@ -84,6 +85,7 @@ impl Command {
             args: Vec::new(),
             env: None,
             cwd: None,
+            flags: 0,
             detach: false,
             stdin: None,
             stdout: None,
@@ -124,6 +126,9 @@ impl Command {
     pub fn stderr(&mut self, stderr: Stdio) {
         self.stderr = Some(stderr);
     }
+    pub fn creation_flags(&mut self, flags: u32) {
+        self.flags = flags;
+    }
 
     pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                  -> io::Result<(Process, StdioPipes)> {
@@ -157,7 +162,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;
         }