Skip to content

Commit

Permalink
Auto merge of #75005 - adamreichold:limit-vector-count, r=Amanieu
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Aug 5, 2020
2 parents db870ea + 9073acd commit 52b179b
Showing 1 changed file with 38 additions and 2 deletions.
40 changes: 38 additions & 2 deletions library/std/src/sys/unix/fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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 }
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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());
}
}

0 comments on commit 52b179b

Please sign in to comment.