Skip to content

Commit 5530ff4

Browse files
authored
Merge pull request #57 from NobodyXu/feat/unlimited-from-env
feat: Make `Client::from_env` safe to call for any number of times
2 parents 799eacc + 1c44c55 commit 5530ff4

File tree

2 files changed

+26
-15
lines changed

2 files changed

+26
-15
lines changed

src/lib.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,6 @@ impl Client {
231231
/// result with the connected client will be returned. In other cases
232232
/// result will contain `Err(FromEnvErr)`.
233233
///
234-
/// Note that on Unix the `Client` returned **takes ownership of the file
235-
/// descriptors specified in the environment**. Jobservers on Unix are
236-
/// implemented with `pipe` file descriptors, and they're inherited from
237-
/// parent processes. This `Client` returned takes ownership of the file
238-
/// descriptors for this process and will close the file descriptors after
239-
/// this value is dropped.
240-
///
241234
/// Additionally on Unix this function will configure the file descriptors
242235
/// with `CLOEXEC` so they're not automatically inherited by spawned
243236
/// children.
@@ -256,11 +249,7 @@ impl Client {
256249
/// make sure to take ownership properly of the file descriptors passed
257250
/// down, if any.
258251
///
259-
/// It's generally unsafe to call this function twice in a program if the
260-
/// previous invocation returned `Some`.
261-
///
262-
/// Note, though, that on Windows it should be safe to call this function
263-
/// any number of times.
252+
/// It is ok to call this function any number of times.
264253
pub unsafe fn from_env_ext(check_pipe: bool) -> FromEnv {
265254
let (env, var_os) = match ["CARGO_MAKEFLAGS", "MAKEFLAGS", "MFLAGS"]
266255
.iter()
@@ -293,6 +282,19 @@ impl Client {
293282
/// environment.
294283
///
295284
/// Wraps `from_env_ext` and discards error details.
285+
///
286+
/// # Safety
287+
///
288+
/// This function is `unsafe` to call on Unix specifically as it
289+
/// transitively requires usage of the `from_raw_fd` function, which is
290+
/// itself unsafe in some circumstances.
291+
///
292+
/// It's recommended to call this function very early in the lifetime of a
293+
/// program before any other file descriptors are opened. That way you can
294+
/// make sure to take ownership properly of the file descriptors passed
295+
/// down, if any.
296+
///
297+
/// It is ok to call this function any number of times.
296298
pub unsafe fn from_env() -> Option<Client> {
297299
Self::from_env_ext(false).client.ok()
298300
}

src/unix.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,10 @@ impl Client {
158158
}
159159
}
160160

161-
drop(set_cloexec(read, true));
162-
drop(set_cloexec(write, true));
163-
Ok(Some(Client::from_fds(read, write)))
161+
Ok(Some(Client::Pipe {
162+
read: clone_fd_and_set_cloexec(read)?,
163+
write: clone_fd_and_set_cloexec(write)?,
164+
}))
164165
}
165166

166167
unsafe fn from_fds(read: c_int, write: c_int) -> Client {
@@ -444,6 +445,14 @@ unsafe fn fd_check(fd: c_int, check_pipe: bool) -> Result<(), FromEnvErrorInner>
444445
}
445446
}
446447

448+
fn clone_fd_and_set_cloexec(fd: c_int) -> Result<File, FromEnvErrorInner> {
449+
// Safety: fd is a valid fd dand it remains open until returns
450+
unsafe { BorrowedFd::borrow_raw(fd) }
451+
.try_clone_to_owned()
452+
.map(File::from)
453+
.map_err(|err| FromEnvErrorInner::CannotOpenFd(fd, err))
454+
}
455+
447456
fn set_cloexec(fd: c_int, set: bool) -> io::Result<()> {
448457
unsafe {
449458
let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?;

0 commit comments

Comments
 (0)