Auto merge of #75005 - adamreichold:limit-vector-count, r=Amanieu
Limit I/O vector count on Unix Unix systems enforce limits on the vector count when performing vectored I/O via the readv and writev system calls and return EINVAL when these limits are exceeded. This changes the standard library to handle those limits as short reads and writes to avoid forcing its users to query these limits using platform specific mechanisms. Fixes #68042
This commit is contained in:
commit
52b179b4b5
@ -3,6 +3,8 @@
|
||||
use crate::cmp;
|
||||
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
|
||||
use crate::mem;
|
||||
#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
|
||||
use crate::sync::atomic::{AtomicUsize, Ordering};
|
||||
use crate::sys::cvt;
|
||||
use crate::sys_common::AsInner;
|
||||
|
||||
@ -26,6 +28,27 @@ const READ_LIMIT: usize = c_int::MAX as usize - 1;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
|
||||
|
||||
#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
|
||||
fn max_iov() -> usize {
|
||||
static LIM: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
let mut lim = LIM.load(Ordering::Relaxed);
|
||||
if lim == 0 {
|
||||
let ret = unsafe { libc::sysconf(libc::_SC_IOV_MAX) };
|
||||
|
||||
// 16 is the minimum value required by POSIX.
|
||||
lim = if ret > 0 { ret as usize } else { 16 };
|
||||
LIM.store(lim, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
lim
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "redox", target_env = "newlib"))]
|
||||
fn max_iov() -> usize {
|
||||
16 // The minimum value required by POSIX.
|
||||
}
|
||||
|
||||
impl FileDesc {
|
||||
pub fn new(fd: c_int) -> FileDesc {
|
||||
FileDesc { fd }
|
||||
@ -54,7 +77,7 @@ impl FileDesc {
|
||||
libc::readv(
|
||||
self.fd,
|
||||
bufs.as_ptr() as *const libc::iovec,
|
||||
cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
|
||||
cmp::min(bufs.len(), max_iov()) as c_int,
|
||||
)
|
||||
})?;
|
||||
Ok(ret as usize)
|
||||
@ -111,7 +134,7 @@ impl FileDesc {
|
||||
libc::writev(
|
||||
self.fd,
|
||||
bufs.as_ptr() as *const libc::iovec,
|
||||
cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
|
||||
cmp::min(bufs.len(), max_iov()) as c_int,
|
||||
)
|
||||
})?;
|
||||
Ok(ret as usize)
|
||||
@ -256,3 +279,16 @@ impl Drop for FileDesc {
|
||||
let _ = unsafe { libc::close(self.fd) };
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{FileDesc, IoSlice};
|
||||
|
||||
#[test]
|
||||
fn limit_vector_count() {
|
||||
let stdout = FileDesc { fd: 1 };
|
||||
let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();
|
||||
|
||||
assert!(stdout.write_vectored(&bufs).is_ok());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user