From a25b0946a79744c1f39ca759ab7db4081a2ebb51 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 28 Apr 2024 13:50:11 +0100 Subject: [PATCH 1/9] std::net: Socket::new_raw set to SO_NOSIGPIPE on freebsd/netbsd/dragonfly. --- library/std/src/sys/pal/unix/net.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index 7237989c9059b..b8dc1538a6378 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -86,7 +86,14 @@ impl Socket { // flag to atomically create the socket and set it as // CLOEXEC. On Linux this was added in 2.6.27. let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?; - Ok(Socket(FileDesc::from_raw_fd(fd))) + let socket = Socket(FileDesc::from_raw_fd(fd)); + + // DragonFlyBSD, FreeBSD and NetBSD use `SO_NOSIGPIPE` as a `setsockopt` + // flag to disable `SIGPIPE` emission on socket. + #[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "dragonfly"))] + setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?; + + Ok(socket) } else { let fd = cvt(libc::socket(fam, ty, 0))?; let fd = FileDesc::from_raw_fd(fd); From ab066ae329d0f56cfbb551d0c0f4b1121ae30477 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 6 May 2024 09:52:13 +0900 Subject: [PATCH 2/9] add note about `AlreadyExists` to `create_new` --- library/std/src/fs.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 409ead0e28433..911bc8cabe29c 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -408,6 +408,7 @@ impl File { /// /// This function will create a file if it does not exist, or return an error if it does. This /// way, if the call succeeds, the file returned is guaranteed to be new. + /// If a file exists at the target location before, creating file will fail with [`AlreadyExists`]. /// /// This option is useful because it is atomic. Otherwise between checking whether a file /// exists and creating a new one, the file may have been created by another process (a TOCTOU @@ -416,6 +417,8 @@ impl File { /// This can also be written using /// `File::options().read(true).write(true).create_new(true).open(...)`. /// + /// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists + /// /// # Examples /// /// ```no_run @@ -1071,6 +1074,7 @@ impl OpenOptions { /// /// No file is allowed to exist at the target location, also no (dangling) symlink. In this /// way, if the call succeeds, the file returned is guaranteed to be new. + /// If a file exists at the target location before, creating file will fail with [`AlreadyExists`]. /// /// This option is useful because it is atomic. Otherwise between checking /// whether a file exists and creating a new one, the file may have been @@ -1084,6 +1088,7 @@ impl OpenOptions { /// /// [`.create()`]: OpenOptions::create /// [`.truncate()`]: OpenOptions::truncate + /// [`AlreadyExists`]: io::ErrorKind::AlreadyExists /// /// # Examples /// From c64889c537830e75311c4d6c48e9d243e8c97e23 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 6 May 2024 02:30:52 +0200 Subject: [PATCH 3/9] iOS/tvOS/watchOS/visionOS: Default to kernel-defined backlog in listen This behavior is defined in general for the XNU kernel, not just macOS: https://github.com/apple-oss-distributions/xnu/blob/rel/xnu-10002/bsd/kern/uipc_socket.c --- library/std/src/os/unix/net/listener.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 7e53acbc3878a..a55199c82fc10 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -81,21 +81,25 @@ impl UnixListener { ))] const backlog: core::ffi::c_int = 128; #[cfg(any( + // Silently capped to `/proc/sys/net/core/somaxconn`. target_os = "linux", + // Silently capped to `kern.ipc.soacceptqueue`. target_os = "freebsd", + // Silently capped to `kern.somaxconn sysctl`. target_os = "openbsd", - target_os = "macos" + // Silently capped to the default 128. + target_vendor = "apple", ))] const backlog: core::ffi::c_int = -1; #[cfg(not(any( target_os = "windows", target_os = "redox", + target_os = "espidf", + target_os = "horizon", target_os = "linux", target_os = "freebsd", target_os = "openbsd", - target_os = "macos", - target_os = "espidf", - target_os = "horizon" + target_vendor = "apple", )))] const backlog: libc::c_int = libc::SOMAXCONN; From 81f5175868eefa9a12b27377c9fc474d7033cee6 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Mon, 6 May 2024 12:16:31 +0900 Subject: [PATCH 4/9] Apply suggestions from code review Co-authored-by: Jubilee <46493976+workingjubilee@users.noreply.github.com> --- library/std/src/fs.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 911bc8cabe29c..fb607e055920c 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -408,7 +408,9 @@ impl File { /// /// This function will create a file if it does not exist, or return an error if it does. This /// way, if the call succeeds, the file returned is guaranteed to be new. - /// If a file exists at the target location before, creating file will fail with [`AlreadyExists`]. + /// If a file exists at the target location, creating a new file will fail with [`AlreadyExists`] + /// or another error based on the situation. See [`OpenOptions::open`] for a + /// non-exhaustive list of likely errors. /// /// This option is useful because it is atomic. Otherwise between checking whether a file /// exists and creating a new one, the file may have been created by another process (a TOCTOU @@ -1074,7 +1076,9 @@ impl OpenOptions { /// /// No file is allowed to exist at the target location, also no (dangling) symlink. In this /// way, if the call succeeds, the file returned is guaranteed to be new. - /// If a file exists at the target location before, creating file will fail with [`AlreadyExists`]. + /// If a file exists at the target location, creating a new file will fail with [`AlreadyExists`] + /// or another error based on the situation. See [`OpenOptions::open`] for a + /// non-exhaustive list of likely errors. /// /// This option is useful because it is atomic. Otherwise between checking /// whether a file exists and creating a new one, the file may have been From aa606bb246596dfc6797caa4570025e6f99457c3 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 6 May 2024 02:40:48 +0200 Subject: [PATCH 5/9] iOS/tvOS/watchOS/visionOS: Set the main thread name Tested in the iOS simulator that the thread name is not set by default, and that setting it improves the debugging experience in lldb / Xcode. --- library/std/src/sys/pal/unix/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 1ac5729c02fd4..21f233e22620c 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -63,11 +63,11 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { args::init(argc, argv); // Normally, `thread::spawn` will call `Thread::set_name` but since this thread - // already exists, we have to call it ourselves. We only do this on macos + // already exists, we have to call it ourselves. We only do this on Apple targets // because some unix-like operating systems such as Linux share process-id and // thread-id for the main thread and so renaming the main thread will rename the // process and we only want to enable this on platforms we've tested. - if cfg!(target_os = "macos") { + if cfg!(target_vendor = "apple") { thread::Thread::set_name(&c"main"); } From 53bd38b7c5d5dc43feced7cf76904fa5b788de0c Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 6 May 2024 07:56:41 +0200 Subject: [PATCH 6/9] iOS/tvOS/watchOS: Fix alloc w. large alignment on older versions Tested on an old MacBook and the iOS simulator. --- library/std/src/sys/pal/unix/alloc.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/alloc.rs b/library/std/src/sys/pal/unix/alloc.rs index af0089978ecbb..9938c0bac25b0 100644 --- a/library/std/src/sys/pal/unix/alloc.rs +++ b/library/std/src/sys/pal/unix/alloc.rs @@ -13,7 +13,13 @@ unsafe impl GlobalAlloc for System { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { libc::malloc(layout.size()) as *mut u8 } else { - #[cfg(target_os = "macos")] + // `posix_memalign` returns a non-aligned value if supplied a very + // large alignment on older versions of Apple's platforms (unknown + // exactly which version range, but the issue is definitely + // present in macOS 10.14 and iOS 13.3). + // + // + #[cfg(target_vendor = "apple")] { if layout.align() > (1 << 31) { return ptr::null_mut(); From 28622c9e526ea3d1bd31eba546fc73eeb717752a Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 6 May 2024 07:52:57 +0200 Subject: [PATCH 7/9] iOS/tvOS/watchOS/visionOS: Fix reading large files Tested in the iOS simulator with something like: ``` let mut buf = vec![0; c_int::MAX as usize - 1 + 2]; let read_bytes = f.read(&mut buf).unwrap(); ``` --- library/std/src/sys/pal/unix/fd.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index 203c7180001f5..1701717db597c 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -33,14 +33,15 @@ pub struct FileDesc(OwnedFd); // with the man page quoting that if the count of bytes to read is // greater than `SSIZE_MAX` the result is "unspecified". // -// On macOS, however, apparently the 64-bit libc is either buggy or +// On Apple targets however, apparently the 64-bit libc is either buggy or // intentionally showing odd behavior by rejecting any read with a size // larger than or equal to INT_MAX. To handle both of these the read // size is capped on both platforms. -#[cfg(target_os = "macos")] -const READ_LIMIT: usize = libc::c_int::MAX as usize - 1; -#[cfg(not(target_os = "macos"))] -const READ_LIMIT: usize = libc::ssize_t::MAX as usize; +const READ_LIMIT: usize = if cfg!(target_vendor = "apple") { + libc::c_int::MAX as usize - 1 +} else { + libc::ssize_t::MAX as usize +}; #[cfg(any( target_os = "dragonfly", From ff41c99bb88b0309f5400f2c69d2ecccf3dbbb14 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 6 May 2024 08:20:48 +0200 Subject: [PATCH 8/9] iOS/tvOS/watchOS/visionOS: Improve File Debug impl This uses `libc::fcntl`, which, while not explicitly marked as available in the headers, is already used by `File::sync_all` and `File::sync_data` on these platforms, so should be fine to use here as well. --- library/std/src/sys/pal/unix/fs.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 32cdd13fbebda..fbbd40bfb796a 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -1493,11 +1493,11 @@ impl fmt::Debug for File { readlink(&p).ok() } - #[cfg(target_os = "macos")] + #[cfg(target_vendor = "apple")] fn get_path(fd: c_int) -> Option { // FIXME: The use of PATH_MAX is generally not encouraged, but it - // is inevitable in this case because macOS defines `fcntl` with - // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no + // is inevitable in this case because Apple targets define `fcntl` + // with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no // alternatives. If a better method is invented, it should be used // instead. let mut buf = vec![0; libc::PATH_MAX as usize]; @@ -1538,12 +1538,12 @@ impl fmt::Debug for File { #[cfg(not(any( target_os = "linux", - target_os = "macos", target_os = "vxworks", all(target_os = "freebsd", target_arch = "x86_64"), target_os = "netbsd", target_os = "illumos", - target_os = "solaris" + target_os = "solaris", + target_vendor = "apple", )))] fn get_path(_fd: c_int) -> Option { // FIXME(#24570): implement this for other Unix platforms @@ -1552,12 +1552,12 @@ impl fmt::Debug for File { #[cfg(any( target_os = "linux", - target_os = "macos", target_os = "freebsd", target_os = "hurd", target_os = "netbsd", target_os = "openbsd", - target_os = "vxworks" + target_os = "vxworks", + target_vendor = "apple", ))] fn get_mode(fd: c_int) -> Option<(bool, bool)> { let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; @@ -1574,12 +1574,12 @@ impl fmt::Debug for File { #[cfg(not(any( target_os = "linux", - target_os = "macos", target_os = "freebsd", target_os = "hurd", target_os = "netbsd", target_os = "openbsd", - target_os = "vxworks" + target_os = "vxworks", + target_vendor = "apple", )))] fn get_mode(_fd: c_int) -> Option<(bool, bool)> { // FIXME(#24570): implement this for other Unix platforms From 776f182241ca224c459356a3c30ea9bef6611971 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 May 2024 10:48:04 +0200 Subject: [PATCH 9/9] next_power_of_two: add a doctest to show what happens on 0 --- library/core/src/num/uint_macros.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 673144cb32827..48a96c5792c64 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2764,6 +2764,7 @@ macro_rules! uint_impl { /// ``` #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2);")] #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".next_power_of_two(), 1);")] /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]