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