Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit de0672f

Browse files
Ensure at least one buffer for vectored I/O
POSIX requires at least one buffer passed to readv and writev, but we allow the user to pass an empty slice of buffers. In this case, return a zero-length read or write.
1 parent 82ebd46 commit de0672f

File tree

5 files changed

+86
-84
lines changed

5 files changed

+86
-84
lines changed

‎library/std/src/io/mod.rs

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,24 +1389,6 @@ impl<'a> IoSliceMut<'a> {
13891389
}
13901390
}
13911391

1392-
/// Limits a slice of buffers to at most `n` buffers.
1393-
///
1394-
/// When the slice contains over `n` buffers, ensure that at least one
1395-
/// non-empty buffer is in the truncated slice, if there is one.
1396-
#[inline]
1397-
pub(crate) fn limit_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) {
1398-
if intrinsics::unlikely(bufs.len() > n) {
1399-
for (i, buf) in bufs.iter().enumerate() {
1400-
if !buf.is_empty() {
1401-
let len = cmp::min(bufs.len() - i, n);
1402-
*bufs = &mut take(bufs)[i..i + len];
1403-
return;
1404-
}
1405-
}
1406-
*bufs = &mut take(bufs)[..0];
1407-
}
1408-
}
1409-
14101392
/// Get the underlying bytes as a mutable slice with the original lifetime.
14111393
///
14121394
/// # Examples
@@ -1568,24 +1550,6 @@ impl<'a> IoSlice<'a> {
15681550
}
15691551
}
15701552

1571-
/// Limits a slice of buffers to at most `n` buffers.
1572-
///
1573-
/// When the slice contains over `n` buffers, ensure that at least one
1574-
/// non-empty buffer is in the truncated slice, if there is one.
1575-
#[inline]
1576-
pub(crate) fn limit_slices(bufs: &mut &[IoSlice<'a>], n: usize) {
1577-
if intrinsics::unlikely(bufs.len() > n) {
1578-
for (i, buf) in bufs.iter().enumerate() {
1579-
if !buf.is_empty() {
1580-
let len = cmp::min(bufs.len() - i, n);
1581-
*bufs = &bufs[i..i + len];
1582-
return;
1583-
}
1584-
}
1585-
*bufs = &bufs[..0];
1586-
}
1587-
}
1588-
15891553
/// Get the underlying bytes as a slice with the original lifetime.
15901554
///
15911555
/// This doesn't borrow from `self`, so is less restrictive than calling
@@ -1623,6 +1587,60 @@ impl<'a> Deref for IoSlice<'a> {
16231587
}
16241588
}
16251589

1590+
/// Limits a slice of buffers to at most `n` buffers and ensures that it has at
1591+
/// least one buffer, even if empty.
1592+
///
1593+
/// When the slice contains over `n` buffers, ensure that at least one non-empty
1594+
/// buffer is in the truncated slice, if there is one.
1595+
#[allow(unused)] // Not used on all platforms
1596+
pub(crate) macro limit_slices($bufs:expr, $n:expr) {
1597+
'slices: {
1598+
let bufs: &[IoSlice<'_>] = $bufs;
1599+
let n: usize = $n;
1600+
// if bufs.len() > n || bufs.is_empty()
1601+
if intrinsics::unlikely(bufs.len().wrapping_sub(1) > n - 1) {
1602+
for (i, buf) in bufs.iter().enumerate() {
1603+
if !buf.is_empty() {
1604+
let len = cmp::min(bufs.len() - i, n);
1605+
break 'slices &bufs[i..i + len];
1606+
}
1607+
}
1608+
// All buffers are empty. Since POSIX requires at least one buffer
1609+
// for [writev], but possibly bufs.is_empty(), return an empty write.
1610+
// [writev]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/writev.html
1611+
return Ok(0);
1612+
}
1613+
bufs
1614+
}
1615+
}
1616+
1617+
/// Limits a slice of buffers to at most `n` buffers and ensures that it has at
1618+
/// least one buffer, even if empty.
1619+
///
1620+
/// When the slice contains over `n` buffers, ensure that at least one non-empty
1621+
/// buffer is in the truncated slice, if there is one.
1622+
#[allow(unused)] // Not used on all platforms
1623+
pub(crate) macro limit_slices_mut($bufs:expr, $n:expr) {
1624+
'slices: {
1625+
let bufs: &mut [IoSliceMut<'_>] = $bufs;
1626+
let n: usize = $n;
1627+
// if bufs.len() > n || bufs.is_empty()
1628+
if intrinsics::unlikely(bufs.len().wrapping_sub(1) > n - 1) {
1629+
for (i, buf) in bufs.iter().enumerate() {
1630+
if !buf.is_empty() {
1631+
let len = cmp::min(bufs.len() - i, n);
1632+
break 'slices &mut bufs[i..i + len];
1633+
}
1634+
}
1635+
// All buffers are empty. Since POSIX requires at least one buffer
1636+
// for [readv], but possibly bufs.is_empty(), return an empty read.
1637+
// [readv]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/readv.html
1638+
return Ok(0);
1639+
}
1640+
bufs
1641+
}
1642+
}
1643+
16261644
/// A trait for objects which are byte-oriented sinks.
16271645
///
16281646
/// Implementors of the `Write` trait are sometimes called 'writers'.

‎library/std/src/sys/net/connection/socket/solid.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,8 @@ impl Socket {
222222
self.recv_with_flags(buf, 0)
223223
}
224224

225-
pub fn read_vectored(&self, mutbufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
226-
IoSliceMut::limit_slices(&mutbufs, max_iov());
225+
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
226+
let bufs = io::limit_slices_mut!(bufs, max_iov());
227227
let ret = cvt(unsafe {
228228
netc::readv(self.as_raw_fd(), bufs.as_ptr() as *const netc::iovec, bufs.len() as c_int)
229229
})?;
@@ -264,8 +264,8 @@ impl Socket {
264264
self.recv_from_with_flags(buf, MSG_PEEK)
265265
}
266266

267-
pub fn write_vectored(&self, mutbufs: &[IoSlice<'_>]) -> io::Result<usize> {
268-
IoSlice::limit_slices(&mutbufs, max_iov());
267+
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
268+
let bufs = io::limit_slices!(bufs, max_iov());
269269
let ret = cvt(unsafe {
270270
netc::writev(self.as_raw_fd(), bufs.as_ptr() as *const netc::iovec, bufs.len() as c_int)
271271
})?;

‎library/std/src/sys/net/connection/socket/windows.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,8 @@ impl Socket {
333333
self.recv_with_flags(buf, 0)
334334
}
335335

336-
pub fn read_vectored(&self, mutbufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
337-
IoSliceMut::limit_slices(&mutbufs, u32::MAX as usize);
336+
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
337+
let bufs = io::limit_slices_mut!(bufs, u32::MAX as usize);
338338
let mut nread = 0;
339339
let mut flags = 0;
340340
let result = unsafe {
@@ -422,8 +422,8 @@ impl Socket {
422422
self.recv_from_with_flags(buf, c::MSG_PEEK)
423423
}
424424

425-
pub fn write_vectored(&self, mutbufs: &[IoSlice<'_>]) -> io::Result<usize> {
426-
IoSlice::limit_slices(&mutbufs, u32::MAX as usize);
425+
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
426+
let bufs = io::limit_slices!(bufs, u32::MAX as usize);
427427
let mut nwritten = 0;
428428
let result = unsafe {
429429
c::WSASend(

‎library/std/src/sys/pal/hermit/fd.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ impl FileDesc {
3737
Ok(())
3838
}
3939

40-
pub fn read_vectored(&self, mutbufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
41-
IoSliceMut::limit_slices(&mutbufs, max_iov());
40+
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
41+
let bufs = io::limit_slices_mut!(bufs, max_iov());
4242
let ret = cvt(unsafe {
4343
hermit_abi::readv(
4444
self.as_raw_fd(),
@@ -65,8 +65,8 @@ impl FileDesc {
6565
Ok(result as usize)
6666
}
6767

68-
pub fn write_vectored(&self, mutbufs: &[IoSlice<'_>]) -> io::Result<usize> {
69-
IoSlice::limit_slices(&mutbufs, max_iov());
68+
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
69+
let bufs = io::limit_slices!(bufs, max_iov());
7070
let ret = cvt(unsafe {
7171
hermit_abi::writev(
7272
self.as_raw_fd(),

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

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ impl FileDesc {
104104
target_os = "vita",
105105
target_os = "nuttx"
106106
)))]
107-
pub fn read_vectored(&self, mutbufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
108-
IoSliceMut::limit_slices(&mutbufs, max_iov());
107+
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
108+
let bufs = io::limit_slices_mut!(bufs, max_iov());
109109
let ret = cvt(unsafe {
110110
libc::readv(
111111
self.as_raw_fd(),
@@ -195,12 +195,8 @@ impl FileDesc {
195195
target_os = "netbsd",
196196
target_os = "openbsd", // OpenBSD 2.7
197197
))]
198-
pub fn read_vectored_at(
199-
&self,
200-
mut bufs: &mut [IoSliceMut<'_>],
201-
offset: u64,
202-
) -> io::Result<usize> {
203-
IoSliceMut::limit_slices(&mut bufs, max_iov());
198+
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
199+
let bufs = io::limit_slices_mut!(bufs, max_iov());
204200
let ret = cvt(unsafe {
205201
libc::preadv(
206202
self.as_raw_fd(),
@@ -237,11 +233,7 @@ impl FileDesc {
237233
// passing 64-bits parameters to syscalls, so we fallback to the default
238234
// implementation if `preadv` is not available.
239235
#[cfg(all(target_os = "android", target_pointer_width = "64"))]
240-
pub fn read_vectored_at(
241-
&self,
242-
mut bufs: &mut [IoSliceMut<'_>],
243-
offset: u64,
244-
) -> io::Result<usize> {
236+
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
245237
super::weak::syscall!(
246238
fn preadv(
247239
fd: libc::c_int,
@@ -251,7 +243,7 @@ impl FileDesc {
251243
) -> isize;
252244
);
253245

254-
IoSliceMut::limit_slices(&mutbufs, max_iov());
246+
let bufs = io::limit_slices_mut!(bufs, max_iov());
255247
let ret = cvt(unsafe {
256248
preadv(
257249
self.as_raw_fd(),
@@ -267,11 +259,7 @@ impl FileDesc {
267259
// FIXME(#115199): Rust currently omits weak function definitions
268260
// and its metadata from LLVM IR.
269261
#[no_sanitize(cfi)]
270-
pub fn read_vectored_at(
271-
&self,
272-
mut bufs: &mut [IoSliceMut<'_>],
273-
offset: u64,
274-
) -> io::Result<usize> {
262+
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
275263
super::weak::weak!(
276264
fn preadv64(
277265
fd: libc::c_int,
@@ -283,7 +271,7 @@ impl FileDesc {
283271

284272
match preadv64.get() {
285273
Some(preadv) => {
286-
IoSliceMut::limit_slices(&mutbufs, max_iov());
274+
let bufs = io::limit_slices_mut!(bufs, max_iov());
287275
let ret = cvt(unsafe {
288276
preadv(
289277
self.as_raw_fd(),
@@ -308,11 +296,7 @@ impl FileDesc {
308296
// These versions may be newer than the minimum supported versions of OS's we support so we must
309297
// use "weak" linking.
310298
#[cfg(target_vendor = "apple")]
311-
pub fn read_vectored_at(
312-
&self,
313-
mut bufs: &mut [IoSliceMut<'_>],
314-
offset: u64,
315-
) -> io::Result<usize> {
299+
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
316300
super::weak::weak!(
317301
fn preadv(
318302
fd: libc::c_int,
@@ -324,7 +308,7 @@ impl FileDesc {
324308

325309
match preadv.get() {
326310
Some(preadv) => {
327-
IoSliceMut::limit_slices(&mutbufs, max_iov());
311+
let bufs = io::limit_slices_mut!(bufs, max_iov());
328312
let ret = cvt(unsafe {
329313
preadv(
330314
self.as_raw_fd(),
@@ -356,8 +340,8 @@ impl FileDesc {
356340
target_os = "vita",
357341
target_os = "nuttx"
358342
)))]
359-
pub fn write_vectored(&self, mutbufs: &[IoSlice<'_>]) -> io::Result<usize> {
360-
IoSlice::limit_slices(&mutbufs, max_iov());
343+
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
344+
let bufs = io::limit_slices!(bufs, max_iov());
361345
let ret = cvt(unsafe {
362346
libc::writev(
363347
self.as_raw_fd(),
@@ -426,8 +410,8 @@ impl FileDesc {
426410
target_os = "netbsd",
427411
target_os = "openbsd", // OpenBSD 2.7
428412
))]
429-
pub fn write_vectored_at(&self, mutbufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
430-
IoSlice::limit_slices(&mutbufs, max_iov());
413+
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
414+
let bufs = io::limit_slices!(bufs, max_iov());
431415
let ret = cvt(unsafe {
432416
libc::pwritev(
433417
self.as_raw_fd(),
@@ -464,7 +448,7 @@ impl FileDesc {
464448
// passing 64-bits parameters to syscalls, so we fallback to the default
465449
// implementation if `pwritev` is not available.
466450
#[cfg(all(target_os = "android", target_pointer_width = "64"))]
467-
pub fn write_vectored_at(&self, mutbufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
451+
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
468452
super::weak::syscall!(
469453
fn pwritev(
470454
fd: libc::c_int,
@@ -474,7 +458,7 @@ impl FileDesc {
474458
) -> isize;
475459
);
476460

477-
IoSlice::limit_slices(&mutbufs, max_iov());
461+
let bufs = io::limit_slices!(bufs, max_iov());
478462
let ret = cvt(unsafe {
479463
pwritev(
480464
self.as_raw_fd(),
@@ -487,7 +471,7 @@ impl FileDesc {
487471
}
488472

489473
#[cfg(all(target_os = "android", target_pointer_width = "32"))]
490-
pub fn write_vectored_at(&self, mutbufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
474+
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
491475
super::weak::weak!(
492476
fn pwritev64(
493477
fd: libc::c_int,
@@ -499,7 +483,7 @@ impl FileDesc {
499483

500484
match pwritev64.get() {
501485
Some(pwritev) => {
502-
IoSlice::limit_slices(&mutbufs, max_iov());
486+
let bufs = io::limit_slices!(bufs, max_iov());
503487
let ret = cvt(unsafe {
504488
pwritev(
505489
self.as_raw_fd(),
@@ -524,7 +508,7 @@ impl FileDesc {
524508
// These versions may be newer than the minimum supported versions of OS's we support so we must
525509
// use "weak" linking.
526510
#[cfg(target_vendor = "apple")]
527-
pub fn write_vectored_at(&self, mutbufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
511+
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
528512
super::weak::weak!(
529513
fn pwritev(
530514
fd: libc::c_int,
@@ -536,7 +520,7 @@ impl FileDesc {
536520

537521
match pwritev.get() {
538522
Some(pwritev) => {
539-
IoSlice::limit_slices(&mutbufs, max_iov());
523+
let bufs = io::limit_slices!(bufs, max_iov());
540524
let ret = cvt(unsafe {
541525
pwritev(
542526
self.as_raw_fd(),

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /