about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/win32_os.rs14
-rw-r--r--src/rt/rust_run_program.cpp21
-rw-r--r--src/test/stdtest/run.rs51
3 files changed, 80 insertions, 6 deletions
diff --git a/src/lib/win32_os.rs b/src/lib/win32_os.rs
index 65ee769fb5c..c502ebbfcb7 100644
--- a/src/lib/win32_os.rs
+++ b/src/lib/win32_os.rs
@@ -38,6 +38,7 @@ mod libc_constants {
     fn O_TRUNC() -> int { ret 512; }
     fn O_TEXT() -> int { ret 16384; }
     fn O_BINARY() -> int { ret 32768; }
+    fn O_NOINHERIT() -> int { ret 0x0080; }
     fn S_IRUSR() -> uint {
         ret 256u; // really _S_IREAD  in win32
 
@@ -60,9 +61,18 @@ fn target_os() -> str { ret "win32"; }
 fn dylib_filename(base: str) -> str { ret base + ".dll"; }
 
 fn pipe() -> {in: int, out: int} {
+    // Windows pipes work subtly differently than unix pipes, and their
+    // inheritance has to be handled in a different way that I don't fully
+    // understand. Here we explicitly make the pipe non-inheritable,
+    // which means to pass it to a subprocess they need to be duplicated
+    // first, as in rust_run_program.
     let fds = {mutable in: 0, mutable out: 0};
-    assert (os::libc::_pipe(ptr::addr_of(fds.in), 1024u,
-                            libc_constants::O_BINARY()) == 0);
+    let res = os::libc::_pipe(ptr::addr_of(fds.in), 1024u,
+                            libc_constants::O_BINARY()
+                            | libc_constants::O_NOINHERIT());
+    assert res == 0;
+    assert fds.in != -1 && fds.in != 0;
+    assert fds.out != -1 && fds.in != 0;
     ret {in: fds.in, out: fds.out};
 }
 
diff --git a/src/rt/rust_run_program.cpp b/src/rt/rust_run_program.cpp
index c89aaf6bcbd..69f3cf7e146 100644
--- a/src/rt/rust_run_program.cpp
+++ b/src/rt/rust_run_program.cpp
@@ -12,9 +12,20 @@ rust_run_program(void* task, const char* argv[],
     ZeroMemory(&si, sizeof(STARTUPINFO));
     si.cb = sizeof(STARTUPINFO);
     si.dwFlags = STARTF_USESTDHANDLES;
-    si.hStdInput = (HANDLE)_get_osfhandle(in_fd ? in_fd : 0);
-    si.hStdOutput = (HANDLE)_get_osfhandle(out_fd ? out_fd : 1);
-    si.hStdError = (HANDLE)_get_osfhandle(err_fd ? err_fd : 2);
+
+    HANDLE curproc = GetCurrentProcess();
+    HANDLE origStdin = (HANDLE)_get_osfhandle(in_fd ? in_fd : 0);
+    if (!DuplicateHandle(curproc, origStdin,
+        curproc, &si.hStdInput, 0, 1, DUPLICATE_SAME_ACCESS))
+        return -1;
+    HANDLE origStdout = (HANDLE)_get_osfhandle(out_fd ? out_fd : 1);
+    if (!DuplicateHandle(curproc, origStdout,
+        curproc, &si.hStdOutput, 0, 1, DUPLICATE_SAME_ACCESS))
+        return -1;
+    HANDLE origStderr = (HANDLE)_get_osfhandle(err_fd ? err_fd : 2);
+    if (!DuplicateHandle(curproc, origStderr,
+        curproc, &si.hStdError, 0, 1, DUPLICATE_SAME_ACCESS))
+        return -1;
 
     size_t cmd_len = 0;
     for (const char** arg = argv; *arg; arg++) {
@@ -32,6 +43,10 @@ rust_run_program(void* task, const char* argv[],
     PROCESS_INFORMATION pi;
     BOOL created = CreateProcess(NULL, cmd, NULL, NULL, TRUE,
                                  0, NULL, NULL, &si, &pi);
+                                 
+    CloseHandle(si.hStdInput);
+    CloseHandle(si.hStdOutput);
+    CloseHandle(si.hStdError);
     free(cmd);
 
     if (!created) return -1;
diff --git a/src/test/stdtest/run.rs b/src/test/stdtest/run.rs
index 8ba4c6a80ec..2adfbbe173e 100644
--- a/src/test/stdtest/run.rs
+++ b/src/test/stdtest/run.rs
@@ -1,5 +1,9 @@
 use std;
 import std::run;
+import std::os;
+import std::io;
+import std::option;
+import std::str;
 
 // Regression test for memory leaks
 #[cfg(target_os = "linux")]
@@ -15,4 +19,49 @@ fn test_leaks() {
 #[cfg(target_os = "win32")]
 #[test]
 #[ignore]
-fn test_leaks() { }
\ No newline at end of file
+fn test_leaks() { }
+
+#[test]
+fn test_pipes() {
+    let pipe_in = os::pipe();
+    let pipe_out = os::pipe();
+    let pipe_err = os::pipe();
+
+    let pid = run::spawn_process("cat", [],
+       pipe_in.in, pipe_out.out, pipe_err.out);
+    os::libc::close(pipe_in.in);
+    os::libc::close(pipe_out.out);
+    os::libc::close(pipe_err.out);    
+    
+    if pid == -1 { fail; }
+    let expected = "test";
+    writeclose(pipe_in.out, expected);
+    let actual = readclose(pipe_out.in);
+    readclose(pipe_err.in);
+    os::waitpid(pid);
+    
+    log expected;
+    log actual;
+    assert expected == actual;
+    
+    fn writeclose(fd: int, s: &str) {
+        let writer = io::new_writer(
+            io::fd_buf_writer(fd, option::none));
+        writer.write_str(s);
+
+        os::libc::close(fd);
+    }
+
+    fn readclose(fd: int) -> str {
+        // Copied from run::program_output
+        let file = os::fd_FILE(fd);
+        let reader = io::new_reader(io::FILE_buf_reader(file, option::none));
+        let buf = "";
+        while !reader.eof() {
+            let bytes = reader.read_bytes(4096u);
+            buf += str::unsafe_from_bytes(bytes);
+        }
+        os::libc::fclose(file);
+        ret buf;
+    }
+}
\ No newline at end of file