From aeea7cf1836fa5a2515984691ef1adf20cabe340 Mon Sep 17 00:00:00 2001 From: SteveLauC Date: Sun, 7 Jan 2024 06:17:31 +0800 Subject: [PATCH] refactor: make dup3 wrapper call the real dup3 (#2268) * refactor: make dup3 wrapper call the real dup3 * fix imports * respond to review --- changelog/2268.fixed.md | 1 + changelog/2268.removed.md | 1 + src/unistd.rs | 42 ++++++++++++++++++++------------------- 3 files changed, 24 insertions(+), 20 deletions(-) create mode 100644 changelog/2268.fixed.md create mode 100644 changelog/2268.removed.md diff --git a/changelog/2268.fixed.md b/changelog/2268.fixed.md new file mode 100644 index 0000000000..108553d984 --- /dev/null +++ b/changelog/2268.fixed.md @@ -0,0 +1 @@ +Changed the `dup3` wrapper to perform a real call to `dup3` instead of emulating it via `dup2` and `fcntl` to get rid of race condition diff --git a/changelog/2268.removed.md b/changelog/2268.removed.md new file mode 100644 index 0000000000..a69aba3a45 --- /dev/null +++ b/changelog/2268.removed.md @@ -0,0 +1 @@ +Removed the `dup3` wrapper on macOS, which was emulated via `dup2` and `fcntl` and could cause a race condition. The `dup3` system call is not supported on macOS. diff --git a/src/unistd.rs b/src/unistd.rs index 93187a67c5..92840f7e8b 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -12,7 +12,17 @@ use crate::fcntl::at_rawfd; use crate::fcntl::AtFlags; #[cfg(feature = "fs")] -use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; +#[cfg(any( + linux_android, + freebsdlike, + solarish, + netbsdlike, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "hurd", + target_os = "redox", +))] +use crate::fcntl::OFlag; #[cfg(all(feature = "fs", bsd))] use crate::sys::stat::FileFlag; #[cfg(feature = "fs")] @@ -426,30 +436,22 @@ pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result { } /// Create a new copy of the specified file descriptor using the specified fd -/// and flags (see [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)). +/// and flags (see [`dup(2)`](https://man7.org/linux/man-pages/man2/dup.2.html)). /// /// This function behaves similar to `dup2()` but allows for flags to be /// specified. +#[cfg(any( + netbsdlike, + solarish, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "linux" +))] pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { - dup3_polyfill(oldfd, newfd, flags) -} + let res = unsafe { libc::dup3(oldfd, newfd, flags.bits()) }; -#[inline] -fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { - if oldfd == newfd { - return Err(Errno::EINVAL); - } - - let fd = dup2(oldfd, newfd)?; - - if flags.contains(OFlag::O_CLOEXEC) { - if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) { - let _ = close(fd); - return Err(e); - } - } - - Ok(fd) + Errno::result(res) } /// Change the current working directory of the calling process (see