-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
libstd: unix process spawning: fix bug with setting stdio #30490
Conversation
r? @brson (rust_highfive has picked a reviewer for you, use r? to override) |
Stdio::Raw(fd@libc::STDERR_FILENO) => match cvt_r(|| libc::dup(fd)) { | ||
Err(_) => fail(output), | ||
Ok(fd) => { | ||
let fd = RawStdio::new(fd); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this use FileDesc
instead of RawStdio
here? (as RawStdio
is just a type alias)
Thanks! Could you be sure to also add a test for this? |
@alexcrichton addressed all comments! I wasn't sure about the right place for such a test, but I think run-pass is a good fit. |
|
||
{ | ||
let stdout = File::create(&stdout_file_path).expect("failed to create stdout file"); | ||
let stderr = File::create(&stderr_file_path).expect("failed to create stderr file"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this test be written without creating files? Keeping everything in-memory is generally better for isolation. I think this should basically just be able to use combinations of pipes, right?
@alexcrichton rewrote the test to use pipes instead of files and to re-exec itself instead of calling a shell |
@bors: r+ 751fce0974dd4f634539c37ba759d13c4f894d09 Thanks! |
http://buildbot.rust-lang.org/builders/auto-win-gnu-64-nopt-t/builds/2525/steps/test/logs/stdio
|
* If the requested descriptors to inherit are stdio descriptors there are situations where they will not be set correctly * Example: parent's stdout --> child's stderr parent's stderr --> child's stdout * Solution: if the requested descriptors for the child are stdio descriptors, `dup` them before overwriting the child's stdio
Doh! Forgot some @alexcrichton @Manishearth should be fixed now |
⌛ Testing commit 7f7a059 with merge 6f86431... |
💔 Test failed - auto-win-msvc-32-opt |
@bors: retry On Mon, Jan 11, 2016 at 3:21 PM, bors notifications@github.com wrote:
|
* If the requested descriptors to inherit are stdio descriptors there are situations where they will not be set correctly * Example: parent's stdout --> child's stderr parent's stderr --> child's stdout * Solution: if the requested descriptors for the child are stdio descriptors, `dup` them before overwriting the child's stdio Example of a program which exhibits the bug: ```rust // stdio.rs use std::io::Write; use std::io::{stdout, stderr}; use std::process::{Command, Stdio}; use std::os::unix::io::FromRawFd; fn main() { stdout().write_all("parent stdout\n".as_bytes()).unwrap(); stderr().write_all("parent stderr\n".as_bytes()).unwrap(); Command::new("sh") .arg("-c") .arg("echo 'child stdout'; echo 'child stderr' 1>&2") .stdin(Stdio::inherit()) .stdout(unsafe { FromRawFd::from_raw_fd(2) }) .stderr(unsafe { FromRawFd::from_raw_fd(1) }) .status() .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }); } ``` Before: ``` $ rustc --version rustc 1.7.0-nightly (8ad12c3 2015-12-19) $ rustc stdio.rs && ./stdio >out 2>err $ cat out parent stdout $ cat err parent stderr child stdout child stderr ``` After (expected): ``` $ rustc --version rustc 1.7.0-dev (712ecce 2015-12-19) $ rustc stdio.rs && ./stdio >out 2>err $ cat out parent stdout child stderr $ cat err parent stderr child stdout ```
I think the original report here shows an program which has undefined behaviour. The documentation for
Calling this on 0, 1 or 2 is clearly wrong. |
are situations where they will not be set correctly
parent's stderr --> child's stdout
descriptors,
dup
them before overwriting the child's stdioExample of a program which exhibits the bug:
Before:
After (expected):