Skip to content

Commit 6b3c4c2

Browse files
coolreader18Oneirical
authored andcommitted
Better comments for set_aux_fd
1 parent f6f9e10 commit 6b3c4c2

File tree

2 files changed

+30
-10
lines changed

2 files changed

+30
-10
lines changed

src/tools/run-make-support/src/command.rs

+25-10
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ impl Command {
152152
}
153153

154154
/// Set an auxiliary stream passed to the process, besides the stdio streams.
155+
///
156+
/// Use with caution - ideally, only set one aux fd; if there are multiple,
157+
/// their old `fd` may overlap with another's `newfd`, and thus will break.
158+
/// If you need more than 1 auxiliary file descriptor, rewrite this function
159+
/// to be able to support that.
155160
#[cfg(unix)]
156161
pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
157162
&mut self,
@@ -161,18 +166,28 @@ impl Command {
161166
use std::os::fd::AsRawFd;
162167
use std::os::unix::process::CommandExt;
163168

169+
let cvt = |x| if x == -1 { Err(std::io::Error::last_os_error()) } else { Ok(()) };
170+
164171
let fd = fd.into();
165-
unsafe {
166-
self.cmd.pre_exec(move || {
167-
let fd = fd.as_raw_fd();
168-
let ret = if fd == newfd {
169-
libc::fcntl(fd, libc::F_SETFD, 0)
170-
} else {
171-
libc::dup2(fd, newfd)
172-
};
173-
if ret == -1 { Err(std::io::Error::last_os_error()) } else { Ok(()) }
174-
});
172+
if fd.as_raw_fd() == newfd {
173+
// if fd is already where we want it, just turn off FD_CLOEXEC
174+
// SAFETY: io-safe: we have ownership over fd
175+
cvt(unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_SETFD, 0) })
176+
.expect("disabling CLOEXEC failed");
177+
// we still unconditionally set the pre_exec function, since it captures
178+
// `fd`, and we want to ensure that it stays open until the fork
175179
}
180+
let pre_exec = move || {
181+
if fd.as_raw_fd() != newfd {
182+
// set newfd to point to the same file as fd
183+
// SAFETY: io-"safe": newfd is. not necessarily an unused fd.
184+
// however, we're
185+
cvt(unsafe { libc::dup2(fd.as_raw_fd(), newfd) })?;
186+
}
187+
Ok(())
188+
};
189+
// SAFETY: dup2 is pre-exec-safe
190+
unsafe { self.cmd.pre_exec(pre_exec) };
176191
self
177192
}
178193

src/tools/run-make-support/src/macros.rs

+5
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ macro_rules! impl_common_helpers {
8181
}
8282

8383
/// Set an auxiliary stream passed to the process, besides the stdio streams.
84+
///
85+
/// Use with caution - ideally, only set one aux fd; if there are multiple,
86+
/// their old `fd` may overlap with another's `newfd`, and thus will break.
87+
/// If you need more than 1 auxiliary file descriptor, rewrite this function
88+
/// to be able to support that.
8489
#[cfg(unix)]
8590
pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
8691
&mut self,

0 commit comments

Comments
 (0)