File descriptors passed to Command::stdout/err/in are not closed after dup2
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
File descriptors passed to Command::stdout/err/in are not closed after dup2 to replace stdout/stderr/stdin. This means the file descriptors passed to Command::stdout/err/in are leaked in the child process.
Example:
use std::fs::File;
use std::process::{Command, Stdio};
fn main() -> std::io::Result<()> {
let file = File::create("output.txt")?;
let mut child = Command::new("echo")
.arg("Hello from the child process!")
.stdout(Stdio::from(file))
.spawn()?;
let status = child.wait()?;
println!("Child exited with status: {}", status);
Ok(())
}
strace -f output (full output is attached):
3903339 dup2(3, 1) = 1
3903339 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
3903339 execve("/home/i509vcb/.cargo/bin/echo", ["echo", "Hello from the child process!"], 0x7fffc66d0a58 /* 75 vars */) = -1 ENOENT (No such file or directory)
3903339 execve("/home/i509vcb/.local/bin/echo", ["echo", "Hello from the child process!"], 0x7fffc66d0a58 /* 75 vars */) = -1 ENOENT (No such file or directory)
3903339 execve("/home/i509vcb/bin/echo", ["echo", "Hello from the child process!"], 0x7fffc66d0a58 /* 75 vars */) = -1 ENOENT (No such file or directory)
3903339 execve("/usr/lib64/ccache/echo", ["echo", "Hello from the child process!"], 0x7fffc66d0a58 /* 75 vars */) = -1 ENOENT (No such file or directory)
3903339 execve("/usr/local/bin/echo", ["echo", "Hello from the child process!"], 0x7fffc66d0a58 /* 75 vars */) = -1 ENOENT (No such file or directory)
3903339 execve("/usr/bin/echo", ["echo", "Hello from the child process!"], 0x7fffc66d0a58 /* 75 vars */ <unfinished ...>
3903338 <... clone3 resumed>) = 3903339
This will leak fd 3 on the child process. Ideally do_exec would close the stdio file descriptors which were overriden after dup2 on the child: https://github.com/rust-lang/rust/blob/2300c2aef7dbc2a7bbbeaa9894d07d459abd9bc6/library/std/src/sys/process/unix/unix.rs#L282
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in library/std/src/sys/process/unix/unix.rs at the referenced do_exec implementation and compare the dup2 handling with the attached strace output. Reproduce the example on a Unix system and verify that overridden stdio descriptors are closed in the child after dup2, including the failed-exec path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 38/100