Skip to content

Commit 52b179b

Browse files
committed
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
2 parents db870ea + 9073acd commit 52b179b

File tree

1 file changed

+38
-2
lines changed
  • library/std/src/sys/unix

1 file changed

+38
-2
lines changed

library/std/src/sys/unix/fd.rs

+38-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
use crate::cmp;
44
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
55
use crate::mem;
6+
#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
7+
use crate::sync::atomic::{AtomicUsize, Ordering};
68
use crate::sys::cvt;
79
use crate::sys_common::AsInner;
810

@@ -26,6 +28,27 @@ const READ_LIMIT: usize = c_int::MAX as usize - 1;
2628
#[cfg(not(target_os = "macos"))]
2729
const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
2830

31+
#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
32+
fn max_iov() -> usize {
33+
static LIM: AtomicUsize = AtomicUsize::new(0);
34+
35+
let mut lim = LIM.load(Ordering::Relaxed);
36+
if lim == 0 {
37+
let ret = unsafe { libc::sysconf(libc::_SC_IOV_MAX) };
38+
39+
// 16 is the minimum value required by POSIX.
40+
lim = if ret > 0 { ret as usize } else { 16 };
41+
LIM.store(lim, Ordering::Relaxed);
42+
}
43+
44+
lim
45+
}
46+
47+
#[cfg(any(target_os = "redox", target_env = "newlib"))]
48+
fn max_iov() -> usize {
49+
16 // The minimum value required by POSIX.
50+
}
51+
2952
impl FileDesc {
3053
pub fn new(fd: c_int) -> FileDesc {
3154
FileDesc { fd }
@@ -54,7 +77,7 @@ impl FileDesc {
5477
libc::readv(
5578
self.fd,
5679
bufs.as_ptr() as *const libc::iovec,
57-
cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
80+
cmp::min(bufs.len(), max_iov()) as c_int,
5881
)
5982
})?;
6083
Ok(ret as usize)
@@ -111,7 +134,7 @@ impl FileDesc {
111134
libc::writev(
112135
self.fd,
113136
bufs.as_ptr() as *const libc::iovec,
114-
cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
137+
cmp::min(bufs.len(), max_iov()) as c_int,
115138
)
116139
})?;
117140
Ok(ret as usize)
@@ -256,3 +279,16 @@ impl Drop for FileDesc {
256279
let _ = unsafe { libc::close(self.fd) };
257280
}
258281
}
282+
283+
#[cfg(test)]
284+
mod tests {
285+
use super::{FileDesc, IoSlice};
286+
287+
#[test]
288+
fn limit_vector_count() {
289+
let stdout = FileDesc { fd: 1 };
290+
let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();
291+
292+
assert!(stdout.write_vectored(&bufs).is_ok());
293+
}
294+
}

0 commit comments

Comments
 (0)