]>
Commit | Line | Data |
---|---|---|
b7449926 | 1 | // run-pass |
abe05a73 | 2 | // ignore-emscripten no processes |
48663c56 | 3 | // ignore-sgx no processes |
5bcae85e | 4 | |
9cc50fc6 SL |
5 | // Previously libstd would set stdio descriptors of a child process |
6 | // by `dup`ing the requested descriptors to inherit directly into the | |
7 | // stdio descriptors. This, however, would incorrectly handle cases | |
8 | // where the descriptors to inherit were already stdio descriptors. | |
9 | // This test checks to avoid that regression. | |
10 | ||
0731742a | 11 | #![cfg_attr(unix, feature(rustc_private))] |
9cc50fc6 SL |
12 | #![cfg_attr(windows, allow(unused_imports))] |
13 | ||
14 | #[cfg(unix)] | |
15 | extern crate libc; | |
16 | ||
17 | use std::fs::File; | |
18 | use std::io::{Read, Write}; | |
19 | use std::io::{stdout, stderr}; | |
20 | use std::process::{Command, Stdio}; | |
21 | ||
22 | #[cfg(unix)] | |
23 | use std::os::unix::io::FromRawFd; | |
24 | ||
25 | #[cfg(not(unix))] | |
26 | fn main() { | |
27 | // Bug not present in Windows | |
28 | } | |
29 | ||
30 | #[cfg(unix)] | |
31 | fn main() { | |
32 | let mut args = std::env::args(); | |
33 | let name = args.next().unwrap(); | |
34 | let args: Vec<String> = args.collect(); | |
35 | if let Some("--child") = args.get(0).map(|s| &**s) { | |
36 | return child(); | |
37 | } else if !args.is_empty() { | |
38 | panic!("unknown options"); | |
39 | } | |
40 | ||
41 | let stdout_backup = unsafe { libc::dup(libc::STDOUT_FILENO) }; | |
42 | let stderr_backup = unsafe { libc::dup(libc::STDERR_FILENO) }; | |
43 | assert!(stdout_backup > -1); | |
44 | assert!(stderr_backup > -1); | |
45 | ||
46 | let (stdout_reader, stdout_writer) = pipe(); | |
47 | let (stderr_reader, stderr_writer) = pipe(); | |
48 | assert!(unsafe { libc::dup2(stdout_writer, libc::STDOUT_FILENO) } > -1); | |
49 | assert!(unsafe { libc::dup2(stderr_writer, libc::STDERR_FILENO) } > -1); | |
50 | ||
51 | // Make sure we close any duplicates of the writer end of the pipe, | |
52 | // otherwise we can get stuck reading from the pipe which has open | |
53 | // writers but no one supplying any input | |
54 | assert_eq!(unsafe { libc::close(stdout_writer) }, 0); | |
55 | assert_eq!(unsafe { libc::close(stderr_writer) }, 0); | |
56 | ||
57 | stdout().write_all("parent stdout\n".as_bytes()).expect("failed to write to stdout"); | |
58 | stderr().write_all("parent stderr\n".as_bytes()).expect("failed to write to stderr"); | |
59 | ||
60 | let child = { | |
61 | Command::new(name) | |
62 | .arg("--child") | |
63 | .stdin(Stdio::inherit()) | |
041b39d2 XL |
64 | .stdout(unsafe { Stdio::from_raw_fd(libc::STDERR_FILENO) }) |
65 | .stderr(unsafe { Stdio::from_raw_fd(libc::STDOUT_FILENO) }) | |
9cc50fc6 SL |
66 | .spawn() |
67 | }; | |
68 | ||
69 | // The Stdio passed into the Command took over (and closed) std{out, err} | |
70 | // so we should restore them as they were. | |
71 | assert!(unsafe { libc::dup2(stdout_backup, libc::STDOUT_FILENO) } > -1); | |
72 | assert!(unsafe { libc::dup2(stderr_backup, libc::STDERR_FILENO) } > -1); | |
73 | ||
74 | // Using File as a shim around the descriptor | |
75 | let mut read = String::new(); | |
76 | let mut f: File = unsafe { FromRawFd::from_raw_fd(stdout_reader) }; | |
77 | f.read_to_string(&mut read).expect("failed to read from stdout file"); | |
78 | assert_eq!(read, "parent stdout\nchild stderr\n"); | |
79 | ||
80 | // Using File as a shim around the descriptor | |
81 | read.clear(); | |
82 | let mut f: File = unsafe { FromRawFd::from_raw_fd(stderr_reader) }; | |
83 | f.read_to_string(&mut read).expect("failed to read from stderr file"); | |
84 | assert_eq!(read, "parent stderr\nchild stdout\n"); | |
85 | ||
86 | assert!(child.expect("failed to execute child process").wait().unwrap().success()); | |
87 | } | |
88 | ||
89 | #[cfg(unix)] | |
90 | fn child() { | |
91 | stdout().write_all("child stdout\n".as_bytes()).expect("child failed to write to stdout"); | |
92 | stderr().write_all("child stderr\n".as_bytes()).expect("child failed to write to stderr"); | |
93 | } | |
94 | ||
95 | #[cfg(unix)] | |
96 | /// Returns a pipe (reader, writer combo) | |
97 | fn pipe() -> (i32, i32) { | |
98 | let mut fds = [0; 2]; | |
99 | assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0); | |
100 | (fds[0], fds[1]) | |
101 | } |