]> git.lizzy.rs Git - rust.git/blob - src/test/ui/issues/issue-30490.rs
Auto merge of #87150 - rusticstuff:simplify_wrapping_neg, r=m-ou-se
[rust.git] / src / test / ui / issues / issue-30490.rs
1 // run-pass
2 // ignore-emscripten no processes
3 // ignore-sgx no processes
4
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
11 #![cfg_attr(unix, feature(rustc_private))]
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())
64             .stdout(unsafe { Stdio::from_raw_fd(libc::STDERR_FILENO) })
65             .stderr(unsafe { Stdio::from_raw_fd(libc::STDOUT_FILENO) })
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 }