]> git.proxmox.com Git - rustc.git/blame - src/test/ui/issues/issue-30490.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / src / test / ui / issues / issue-30490.rs
CommitLineData
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)]
15extern crate libc;
16
17use std::fs::File;
18use std::io::{Read, Write};
19use std::io::{stdout, stderr};
20use std::process::{Command, Stdio};
21
22#[cfg(unix)]
23use std::os::unix::io::FromRawFd;
24
25#[cfg(not(unix))]
26fn main() {
27 // Bug not present in Windows
28}
29
30#[cfg(unix)]
31fn 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)]
90fn 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)
97fn 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}