From d3ca7e6913bba3703680cda8a3b9b76a3957e44e Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Sat, 12 Jun 2021 20:39:12 +0200 Subject: [PATCH 1/2] Set FD_CLOEXEC flag on duplicated kqueue Poll Same as commit c52635c76a59be28d0bf287a0bad6d6871a2e36c, but for kqueue. --- src/sys/unix/selector/kqueue.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/unix/selector/kqueue.rs b/src/sys/unix/selector/kqueue.rs index 34f534028..c5b337bca 100644 --- a/src/sys/unix/selector/kqueue.rs +++ b/src/sys/unix/selector/kqueue.rs @@ -87,7 +87,7 @@ impl Selector { } pub fn try_clone(&self) -> io::Result { - syscall!(dup(self.kq)).map(|kq| Selector { + syscall!(fcntl(self.kq, libc::F_DUPFD_CLOEXEC)).map(|kq| Selector { // It's the same selector, so we use the same id. #[cfg(debug_assertions)] id: self.id, From f8734063b20b8934fc35eab801b6c4c05df7725a Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Sun, 13 Jun 2021 00:33:17 +0200 Subject: [PATCH 2/2] Fix Selector::try_clone Calls fcntl F_DUPFD_CLOEXEC expects two arguments; the command (F_DUPFD_CLOEXEC) and an argument for the command. In this case an lower bound for the resulting file descriptor. Because we didn't provide a value it would take whatever value was left in the register from whatever code used it before the system call. This caused Waker::new to fail, see issue https://github.com/tokio-rs/mio/issues/1497. --- src/sys/unix/selector/epoll.rs | 2 +- src/sys/unix/selector/kqueue.rs | 2 +- src/sys/unix/selector/mod.rs | 10 ++++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sys/unix/selector/epoll.rs b/src/sys/unix/selector/epoll.rs index 929e223ba..38667d66c 100644 --- a/src/sys/unix/selector/epoll.rs +++ b/src/sys/unix/selector/epoll.rs @@ -41,7 +41,7 @@ impl Selector { } pub fn try_clone(&self) -> io::Result { - syscall!(fcntl(self.ep, libc::F_DUPFD_CLOEXEC, 0)).map(|ep| Selector { + syscall!(fcntl(self.ep, libc::F_DUPFD_CLOEXEC, super::LOWEST_FD)).map(|ep| Selector { // It's the same selector, so we use the same id. #[cfg(debug_assertions)] id: self.id, diff --git a/src/sys/unix/selector/kqueue.rs b/src/sys/unix/selector/kqueue.rs index c5b337bca..b36a5375e 100644 --- a/src/sys/unix/selector/kqueue.rs +++ b/src/sys/unix/selector/kqueue.rs @@ -87,7 +87,7 @@ impl Selector { } pub fn try_clone(&self) -> io::Result { - syscall!(fcntl(self.kq, libc::F_DUPFD_CLOEXEC)).map(|kq| Selector { + syscall!(fcntl(self.kq, libc::F_DUPFD_CLOEXEC, super::LOWEST_FD)).map(|kq| Selector { // It's the same selector, so we use the same id. #[cfg(debug_assertions)] id: self.id, diff --git a/src/sys/unix/selector/mod.rs b/src/sys/unix/selector/mod.rs index 752589817..b73d645bd 100644 --- a/src/sys/unix/selector/mod.rs +++ b/src/sys/unix/selector/mod.rs @@ -33,3 +33,13 @@ mod kqueue; target_os = "openbsd" ))] pub(crate) use self::kqueue::{event, Event, Events, Selector}; + +/// Lowest file descriptor used in `Selector::try_clone`. +/// +/// # Notes +/// +/// Usually fds 0, 1 and 2 are standard in, out and error. Some application +/// blindly assume this to be true, which means using any one of those a select +/// could result in some interesting and unexpected errors. Avoid that by using +/// an fd that doesn't have a pre-determined usage. +const LOWEST_FD: libc::c_int = 3;