From ca025d88755930b2e2bfd85718134d84c23ba6e1 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sun, 23 Mar 2025 23:02:42 -0700 Subject: [PATCH 1/2] Ensure non-empty buffers for vectored I/O `readv` and `writev` have platform-specific constraints on the number of buffers allowed. For example, on Unix, when the number of buffers passed is zero or over the `IOV_MAX` limit, `EINVAL` is returned. Other platforms have similar constraints. Currently, this is only partially handled in `read_vectored` and `write_vectored` implementations. They truncate the length of the `bufs` slice to `IOV_MAX`, so the slice never exceeds the maximum. However, if the only non-empty buffers are in `bufs[IOV_MAX..]`, the functions will return `Ok(0)`, erroneously signaling EOF. Additionally, the non-zero minimum is not handled. --- library/std/src/io/mod.rs | 58 +++++++++++++++++++ library/std/src/lib.rs | 2 + library/std/src/sys/fd/hermit.rs | 7 ++- library/std/src/sys/fd/unix.rs | 30 ++++++---- library/std/src/sys/fd/unix/tests.rs | 26 ++++++++- .../src/sys/net/connection/socket/solid.rs | 16 ++--- .../src/sys/net/connection/socket/windows.rs | 21 +++++-- 7 files changed, 127 insertions(+), 33 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index ff0e29e04c251..c70472d77ef6a 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1626,6 +1626,64 @@ impl<'a> Deref for IoSlice<'a> { } } +/// Limits a slice of buffers to at most `n` buffers and ensures that it has at +/// least one buffer, even if empty. +/// +/// When the slice contains over `n` buffers, ensure that at least one non-empty +/// buffer is in the truncated slice, if there is one. +#[allow(unused_macros)] // Not used on all platforms +pub(crate) macro limit_slices($bufs:expr, $n:expr) { + 'slices: { + let bufs: &[IoSlice<'_>] = $bufs; + let n: usize = $n; + super let empty = &[IoSlice::new(&[])]; + if bufs.len() > n || bufs.is_empty() { + crate::hint::cold_path(); + for (i, buf) in bufs.iter().enumerate() { + if !buf.is_empty() { + // Take all buffers after the first non-empty buffer, + // clamped to `n`. + let len = cmp::min(bufs.len() - i, n); + break 'slices &bufs[i..i + len]; + } + } + // POSIX requires at least one buffer for writev. + // https://pubs.opengroup.org/onlinepubs/9799919799/functions/writev.html + break 'slices empty; + } + bufs + } +} + +/// Limits a slice of buffers to at most `n` buffers and ensures that it has at +/// least one buffer, even if empty. +/// +/// When the slice contains over `n` buffers, ensure that at least one non-empty +/// buffer is in the truncated slice, if there is one. +#[allow(unused_macros)] // Not used on all platforms +pub(crate) macro limit_slices_mut($bufs:expr, $n:expr) { + 'slices: { + let bufs: &mut [IoSliceMut<'_>] = $bufs; + let n: usize = $n; + super let empty = &mut [IoSliceMut::new(&mut [])]; + if bufs.len() > n || bufs.is_empty() { + crate::hint::cold_path(); + for (i, buf) in bufs.iter().enumerate() { + if !buf.is_empty() { + // Take all buffers after the first non-empty buffer, + // clamped to `n`. + let len = cmp::min(bufs.len() - i, n); + break 'slices &mut bufs[i..i + len]; + } + } + // POSIX requires at least one buffer for readv. + // https://pubs.opengroup.org/onlinepubs/9799919799/functions/readv.html + break 'slices empty; + } + bufs + } +} + /// A trait for objects which are byte-oriented sinks. /// /// Implementors of the `Write` trait are sometimes called 'writers'. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 97db0d6ab7513..e84c896d9854b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -280,6 +280,7 @@ #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] #![feature(char_max_len)] +#![feature(cold_path)] #![feature(const_trait_impl)] #![feature(core_float_math)] #![feature(decl_macro)] @@ -318,6 +319,7 @@ #![feature(staged_api)] #![feature(stmt_expr_attributes)] #![feature(strict_provenance_lints)] +#![feature(super_let)] #![feature(thread_local)] #![feature(try_blocks)] #![feature(try_trait_v2)] diff --git a/library/std/src/sys/fd/hermit.rs b/library/std/src/sys/fd/hermit.rs index 7e8ba065f1b96..793b2bd644885 100644 --- a/library/std/src/sys/fd/hermit.rs +++ b/library/std/src/sys/fd/hermit.rs @@ -1,6 +1,5 @@ #![unstable(reason = "not public", issue = "none", feature = "fd")] -use crate::cmp; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, SeekFrom}; use crate::os::hermit::hermit_abi; use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; @@ -39,11 +38,12 @@ impl FileDesc { } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let bufs = io::limit_slices_mut!(bufs, max_iov()); let ret = cvt(unsafe { hermit_abi::readv( self.as_raw_fd(), bufs.as_mut_ptr() as *mut hermit_abi::iovec as *const hermit_abi::iovec, - cmp::min(bufs.len(), max_iov()), + bufs.len(), ) })?; Ok(ret as usize) @@ -66,11 +66,12 @@ impl FileDesc { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + let bufs = io::limit_slices!(bufs, max_iov()); let ret = cvt(unsafe { hermit_abi::writev( self.as_raw_fd(), bufs.as_ptr() as *const hermit_abi::iovec, - cmp::min(bufs.len(), max_iov()), + bufs.len(), ) })?; Ok(ret as usize) diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index 2b2dfe48e89e2..76fa8bbc9873e 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -126,11 +126,12 @@ impl FileDesc { target_os = "nuttx" )))] pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let bufs = io::limit_slices_mut!(bufs, max_iov()); let ret = cvt(unsafe { libc::readv( self.as_raw_fd(), bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, - cmp::min(bufs.len(), max_iov()) as libc::c_int, + bufs.len() as libc::c_int, ) })?; Ok(ret as usize) @@ -221,11 +222,12 @@ impl FileDesc { target_os = "openbsd", // OpenBSD 2.7 ))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { + let bufs = io::limit_slices_mut!(bufs, max_iov()); let ret = cvt(unsafe { libc::preadv( self.as_raw_fd(), bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, - cmp::min(bufs.len(), max_iov()) as libc::c_int, + bufs.len() as libc::c_int, offset as _, ) })?; @@ -267,11 +269,12 @@ impl FileDesc { ) -> isize; ); + let bufs = io::limit_slices_mut!(bufs, max_iov()); let ret = cvt(unsafe { preadv( self.as_raw_fd(), bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, - cmp::min(bufs.len(), max_iov()) as libc::c_int, + bufs.len() as libc::c_int, offset as _, ) })?; @@ -291,11 +294,12 @@ impl FileDesc { match preadv64.get() { Some(preadv) => { + let bufs = io::limit_slices_mut!(bufs, max_iov()); let ret = cvt(unsafe { preadv( self.as_raw_fd(), bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, - cmp::min(bufs.len(), max_iov()) as libc::c_int, + bufs.len() as libc::c_int, offset as _, ) })?; @@ -327,11 +331,12 @@ impl FileDesc { match preadv.get() { Some(preadv) => { + let bufs = io::limit_slices_mut!(bufs, max_iov()); let ret = cvt(unsafe { preadv( self.as_raw_fd(), bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, - cmp::min(bufs.len(), max_iov()) as libc::c_int, + bufs.len() as libc::c_int, offset as _, ) })?; @@ -359,11 +364,12 @@ impl FileDesc { target_os = "nuttx" )))] pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + let bufs = io::limit_slices!(bufs, max_iov()); let ret = cvt(unsafe { libc::writev( self.as_raw_fd(), bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), max_iov()) as libc::c_int, + bufs.len() as libc::c_int, ) })?; Ok(ret as usize) @@ -427,11 +433,12 @@ impl FileDesc { target_os = "openbsd", // OpenBSD 2.7 ))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { + let bufs = io::limit_slices!(bufs, max_iov()); let ret = cvt(unsafe { libc::pwritev( self.as_raw_fd(), bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), max_iov()) as libc::c_int, + bufs.len() as libc::c_int, offset as _, ) })?; @@ -473,11 +480,12 @@ impl FileDesc { ) -> isize; ); + let bufs = io::limit_slices!(bufs, max_iov()); let ret = cvt(unsafe { pwritev( self.as_raw_fd(), bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), max_iov()) as libc::c_int, + bufs.len() as libc::c_int, offset as _, ) })?; @@ -497,11 +505,12 @@ impl FileDesc { match pwritev64.get() { Some(pwritev) => { + let bufs = io::limit_slices!(bufs, max_iov()); let ret = cvt(unsafe { pwritev( self.as_raw_fd(), bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), max_iov()) as libc::c_int, + bufs.len() as libc::c_int, offset as _, ) })?; @@ -533,11 +542,12 @@ impl FileDesc { match pwritev.get() { Some(pwritev) => { + let bufs = io::limit_slices!(bufs, max_iov()); let ret = cvt(unsafe { pwritev( self.as_raw_fd(), bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), max_iov()) as libc::c_int, + bufs.len() as libc::c_int, offset as _, ) })?; diff --git a/library/std/src/sys/fd/unix/tests.rs b/library/std/src/sys/fd/unix/tests.rs index fcd66c71707d9..9f82b65c00556 100644 --- a/library/std/src/sys/fd/unix/tests.rs +++ b/library/std/src/sys/fd/unix/tests.rs @@ -1,12 +1,32 @@ use core::mem::ManuallyDrop; -use super::FileDesc; +use super::{FileDesc, max_iov}; use crate::io::IoSlice; use crate::os::unix::io::FromRawFd; #[test] fn limit_vector_count() { + const IOV_MAX: usize = max_iov(); + + let stdout = ManuallyDrop::new(unsafe { FileDesc::from_raw_fd(1) }); + let mut bufs = vec![IoSlice::new(&[]); IOV_MAX * 2 + 1]; + assert_eq!(stdout.write_vectored(&bufs).unwrap(), 0); + + // The slice of buffers is truncated to IOV_MAX buffers. However, since the + // first IOV_MAX buffers are all empty, it is sliced starting at the first + // non-empty buffer to avoid erroneously returning Ok(0). In this case, that + // starts with the b"hello" buffer and ends just before the b"world!" + // buffer. + bufs[IOV_MAX] = IoSlice::new(b"hello"); + bufs[IOV_MAX * 2] = IoSlice::new(b"world!"); + assert_eq!(stdout.write_vectored(&bufs).unwrap(), b"hello".len()) +} + +#[test] +fn empty_vector() { + let stdin = ManuallyDrop::new(unsafe { FileDesc::from_raw_fd(0) }); + assert_eq!(stdin.read_vectored(&mut []).unwrap(), 0); + let stdout = ManuallyDrop::new(unsafe { FileDesc::from_raw_fd(1) }); - let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::>(); - assert!(stdout.write_vectored(&bufs).is_ok()); + assert_eq!(stdout.write_vectored(&[]).unwrap(), 0); } diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index 94bb605c1007c..0b979b3c04052 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -9,7 +9,7 @@ use crate::os::solid::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Owne use crate::sys::abi; use crate::sys_common::{FromInner, IntoInner}; use crate::time::Duration; -use crate::{cmp, mem, ptr, str}; +use crate::{mem, ptr, str}; pub(super) mod netc { pub use crate::sys::abi::sockets::*; @@ -223,12 +223,9 @@ impl Socket { } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let bufs = io::limit_slices_mut!(bufs, max_iov()); let ret = cvt(unsafe { - netc::readv( - self.as_raw_fd(), - bufs.as_ptr() as *const netc::iovec, - cmp::min(bufs.len(), max_iov()) as c_int, - ) + netc::readv(self.as_raw_fd(), bufs.as_ptr() as *const netc::iovec, bufs.len() as c_int) })?; Ok(ret as usize) } @@ -268,12 +265,9 @@ impl Socket { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + let bufs = io::limit_slices!(bufs, max_iov()); let ret = cvt(unsafe { - netc::writev( - self.as_raw_fd(), - bufs.as_ptr() as *const netc::iovec, - cmp::min(bufs.len(), max_iov()) as c_int, - ) + netc::writev(self.as_raw_fd(), bufs.as_ptr() as *const netc::iovec, bufs.len() as c_int) })?; Ok(ret as usize) } diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index b71d8b1357b5a..74435faf878a5 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -305,8 +305,6 @@ impl Socket { } fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { - // On unix when a socket is shut down all further reads return 0, so we - // do the same on windows to map a shut down socket to returning EOF. let length = cmp::min(buf.capacity(), i32::MAX as usize) as i32; let result = unsafe { c::recv(self.as_raw(), buf.as_mut().as_mut_ptr() as *mut _, length, flags) }; @@ -315,6 +313,9 @@ impl Socket { c::SOCKET_ERROR => { let error = unsafe { c::WSAGetLastError() }; + // On Unix when a socket is shut down, all further reads return + // 0, so we do the same on Windows to map a shut down socket to + // returning EOF. if error == c::WSAESHUTDOWN { Ok(()) } else { @@ -339,8 +340,9 @@ impl Socket { } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - // On unix when a socket is shut down all further reads return 0, so we - // do the same on windows to map a shut down socket to returning EOF. + // WSARecv requires at least one buffer. + let bufs = if bufs.is_empty() { &mut [IoSliceMut::new(&mut [])] } else { bufs }; + let length = cmp::min(bufs.len(), u32::MAX as usize) as u32; let mut nread = 0; let mut flags = 0; @@ -361,6 +363,9 @@ impl Socket { _ => { let error = unsafe { c::WSAGetLastError() }; + // On Unix when a socket is shut down, all further reads return + // 0, so we do the same on Windows to map a shut down socket to + // returning EOF. if error == c::WSAESHUTDOWN { Ok(0) } else { @@ -390,8 +395,6 @@ impl Socket { let mut addrlen = size_of_val(&storage) as netc::socklen_t; let length = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; - // On unix when a socket is shut down all further reads return 0, so we - // do the same on windows to map a shut down socket to returning EOF. let result = unsafe { c::recvfrom( self.as_raw(), @@ -407,6 +410,9 @@ impl Socket { c::SOCKET_ERROR => { let error = unsafe { c::WSAGetLastError() }; + // On Unix when a socket is shut down, all further reads return + // 0, so we do the same on Windows to map a shut down socket to + // returning EOF. if error == c::WSAESHUTDOWN { Ok((0, unsafe { socket_addr_from_c(&storage, addrlen as usize)? })) } else { @@ -426,6 +432,9 @@ impl Socket { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + // WSASend requires at least one buffer. + let bufs = if bufs.is_empty() { &[IoSlice::new(&[])] } else { bufs }; + let length = cmp::min(bufs.len(), u32::MAX as usize) as u32; let mut nwritten = 0; let result = unsafe { From 53478c6051b7a63eb3b33ed57b75f3542f912ddf Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Thu, 11 Sep 2025 22:42:09 -0600 Subject: [PATCH 2/2] Eliminate use of `super let` --- library/std/src/io/mod.rs | 76 +++++++++++-------- library/std/src/lib.rs | 1 - library/std/src/sys/fd/hermit.rs | 4 +- library/std/src/sys/fd/unix.rs | 20 ++--- .../src/sys/net/connection/socket/solid.rs | 4 +- 5 files changed, 58 insertions(+), 47 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index c70472d77ef6a..c436fa1fc381e 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1631,27 +1631,33 @@ impl<'a> Deref for IoSlice<'a> { /// /// When the slice contains over `n` buffers, ensure that at least one non-empty /// buffer is in the truncated slice, if there is one. +/// +/// For example, [POSIX writev] requires that `bufs.len()` is in `1..=IOV_MAX`. +/// +/// [POSIX writev]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/writev.html #[allow(unused_macros)] // Not used on all platforms -pub(crate) macro limit_slices($bufs:expr, $n:expr) { - 'slices: { - let bufs: &[IoSlice<'_>] = $bufs; - let n: usize = $n; - super let empty = &[IoSlice::new(&[])]; - if bufs.len() > n || bufs.is_empty() { - crate::hint::cold_path(); - for (i, buf) in bufs.iter().enumerate() { +pub(crate) macro limit_slices(&mut $bufs:ident, $n:expr) { + // Rebind $bufs, so the lifetime does not need to live as long as the + // function parameter, and shadow it so the macro caller gets the result. + let mut $bufs: &[IoSlice<'_>] = $bufs; + let n: usize = $n; + + let empty = &[IoSlice::new(&[])]; + + if $bufs.len() > n || $bufs.is_empty() { + crate::hint::cold_path(); + 'fixup: { + // Find the first non-empty buffer and take up to `n` buffers after it. + for (i, buf) in $bufs.iter().enumerate() { if !buf.is_empty() { - // Take all buffers after the first non-empty buffer, - // clamped to `n`. - let len = cmp::min(bufs.len() - i, n); - break 'slices &bufs[i..i + len]; + let len = cmp::min($bufs.len() - i, n); + $bufs = &$bufs[i..i + len]; + break 'fixup; } } - // POSIX requires at least one buffer for writev. - // https://pubs.opengroup.org/onlinepubs/9799919799/functions/writev.html - break 'slices empty; + // If no non-empty buffer is found, use a single empty buffer. + $bufs = empty; } - bufs } } @@ -1660,27 +1666,33 @@ pub(crate) macro limit_slices($bufs:expr, $n:expr) { /// /// When the slice contains over `n` buffers, ensure that at least one non-empty /// buffer is in the truncated slice, if there is one. +/// +/// For example, [POSIX readv] requires that `bufs.len()` is in `1..=IOV_MAX`. +/// +/// [POSIX readv]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/readv.html #[allow(unused_macros)] // Not used on all platforms -pub(crate) macro limit_slices_mut($bufs:expr, $n:expr) { - 'slices: { - let bufs: &mut [IoSliceMut<'_>] = $bufs; - let n: usize = $n; - super let empty = &mut [IoSliceMut::new(&mut [])]; - if bufs.len() > n || bufs.is_empty() { - crate::hint::cold_path(); - for (i, buf) in bufs.iter().enumerate() { +pub(crate) macro limit_slices_mut(&mut $bufs:ident, $n:expr) { + // Rebind $bufs, so the lifetime does not need to live as long as the + // function parameter, and shadow it so the macro caller gets the result. + let mut $bufs: &mut [IoSliceMut<'_>] = $bufs; + let n: usize = $n; + + let empty = &mut [IoSliceMut::new(&mut [])]; + + if $bufs.len() > n || $bufs.is_empty() { + crate::hint::cold_path(); + 'fixup: { + // Find the first non-empty buffer and take up to `n` buffers after it. + for (i, buf) in $bufs.iter().enumerate() { if !buf.is_empty() { - // Take all buffers after the first non-empty buffer, - // clamped to `n`. - let len = cmp::min(bufs.len() - i, n); - break 'slices &mut bufs[i..i + len]; + let len = cmp::min($bufs.len() - i, n); + $bufs = &mut $bufs[i..i + len]; + break 'fixup; } } - // POSIX requires at least one buffer for readv. - // https://pubs.opengroup.org/onlinepubs/9799919799/functions/readv.html - break 'slices empty; + // If no non-empty buffer is found, use a single empty buffer. + $bufs = empty; } - bufs } } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index e84c896d9854b..7c5f1abe9423c 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -319,7 +319,6 @@ #![feature(staged_api)] #![feature(stmt_expr_attributes)] #![feature(strict_provenance_lints)] -#![feature(super_let)] #![feature(thread_local)] #![feature(try_blocks)] #![feature(try_trait_v2)] diff --git a/library/std/src/sys/fd/hermit.rs b/library/std/src/sys/fd/hermit.rs index 793b2bd644885..a646a6b8013eb 100644 --- a/library/std/src/sys/fd/hermit.rs +++ b/library/std/src/sys/fd/hermit.rs @@ -38,7 +38,7 @@ impl FileDesc { } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - let bufs = io::limit_slices_mut!(bufs, max_iov()); + io::limit_slices_mut!(&mut bufs, max_iov()); let ret = cvt(unsafe { hermit_abi::readv( self.as_raw_fd(), @@ -66,7 +66,7 @@ impl FileDesc { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - let bufs = io::limit_slices!(bufs, max_iov()); + io::limit_slices!(&mut bufs, max_iov()); let ret = cvt(unsafe { hermit_abi::writev( self.as_raw_fd(), diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index 76fa8bbc9873e..e07a94c73e61b 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -126,7 +126,7 @@ impl FileDesc { target_os = "nuttx" )))] pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - let bufs = io::limit_slices_mut!(bufs, max_iov()); + io::limit_slices_mut!(&mut bufs, max_iov()); let ret = cvt(unsafe { libc::readv( self.as_raw_fd(), @@ -222,7 +222,7 @@ impl FileDesc { target_os = "openbsd", // OpenBSD 2.7 ))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - let bufs = io::limit_slices_mut!(bufs, max_iov()); + io::limit_slices_mut!(&mut bufs, max_iov()); let ret = cvt(unsafe { libc::preadv( self.as_raw_fd(), @@ -269,7 +269,7 @@ impl FileDesc { ) -> isize; ); - let bufs = io::limit_slices_mut!(bufs, max_iov()); + io::limit_slices_mut!(&mut bufs, max_iov()); let ret = cvt(unsafe { preadv( self.as_raw_fd(), @@ -294,7 +294,7 @@ impl FileDesc { match preadv64.get() { Some(preadv) => { - let bufs = io::limit_slices_mut!(bufs, max_iov()); + io::limit_slices_mut!(&mut bufs, max_iov()); let ret = cvt(unsafe { preadv( self.as_raw_fd(), @@ -331,7 +331,7 @@ impl FileDesc { match preadv.get() { Some(preadv) => { - let bufs = io::limit_slices_mut!(bufs, max_iov()); + io::limit_slices_mut!(&mut bufs, max_iov()); let ret = cvt(unsafe { preadv( self.as_raw_fd(), @@ -364,7 +364,7 @@ impl FileDesc { target_os = "nuttx" )))] pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - let bufs = io::limit_slices!(bufs, max_iov()); + io::limit_slices!(&mut bufs, max_iov()); let ret = cvt(unsafe { libc::writev( self.as_raw_fd(), @@ -433,7 +433,7 @@ impl FileDesc { target_os = "openbsd", // OpenBSD 2.7 ))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - let bufs = io::limit_slices!(bufs, max_iov()); + io::limit_slices!(&mut bufs, max_iov()); let ret = cvt(unsafe { libc::pwritev( self.as_raw_fd(), @@ -480,7 +480,7 @@ impl FileDesc { ) -> isize; ); - let bufs = io::limit_slices!(bufs, max_iov()); + io::limit_slices!(&mut bufs, max_iov()); let ret = cvt(unsafe { pwritev( self.as_raw_fd(), @@ -505,7 +505,7 @@ impl FileDesc { match pwritev64.get() { Some(pwritev) => { - let bufs = io::limit_slices!(bufs, max_iov()); + io::limit_slices!(&mut bufs, max_iov()); let ret = cvt(unsafe { pwritev( self.as_raw_fd(), @@ -542,7 +542,7 @@ impl FileDesc { match pwritev.get() { Some(pwritev) => { - let bufs = io::limit_slices!(bufs, max_iov()); + io::limit_slices!(&mut bufs, max_iov()); let ret = cvt(unsafe { pwritev( self.as_raw_fd(), diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index 0b979b3c04052..60b1b38c0a09a 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -223,7 +223,7 @@ impl Socket { } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - let bufs = io::limit_slices_mut!(bufs, max_iov()); + io::limit_slices_mut!(&mut bufs, max_iov()); let ret = cvt(unsafe { netc::readv(self.as_raw_fd(), bufs.as_ptr() as *const netc::iovec, bufs.len() as c_int) })?; @@ -265,7 +265,7 @@ impl Socket { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - let bufs = io::limit_slices!(bufs, max_iov()); + io::limit_slices!(&mut bufs, max_iov()); let ret = cvt(unsafe { netc::writev(self.as_raw_fd(), bufs.as_ptr() as *const netc::iovec, bufs.len() as c_int) })?;