Avoid writes without any data in Write::write_all_vectored

Previously, when non-empty sequence of empty IoSlices have been provided
to `Write::write_all_vectored`, the buffers would be written as is with
`Write::write_vectored` and subsequently the return value `Ok(0)` would
be misinterpreted as an error.

Avoid writes without any data by advancing the buffers first. This
matches the documented behaviour of `Write::write_all_vectored`
and is analogous to what happens in `Write::write_all`.
This commit is contained in:
Tomasz Miąsko 2020-07-06 00:00:00 +00:00
parent 461707c5a1
commit 7a5d3abfb1

View File

@ -251,7 +251,6 @@
use crate::cmp;
use crate::fmt;
use crate::mem;
use crate::memchr;
use crate::ops::{Deref, DerefMut};
use crate::ptr;
@ -1435,12 +1434,15 @@ fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
/// ```
#[unstable(feature = "write_all_vectored", issue = "70436")]
fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> {
// Guarantee that bufs is empty if it contains no data,
// to avoid calling write_vectored if there is no data to be written.
bufs = IoSlice::advance(bufs, 0);
while !bufs.is_empty() {
match self.write_vectored(bufs) {
Ok(0) => {
return Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"));
}
Ok(n) => bufs = IoSlice::advance(mem::take(&mut bufs), n),
Ok(n) => bufs = IoSlice::advance(bufs, n),
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
@ -2958,6 +2960,7 @@ fn test_write_all_vectored() {
#[rustfmt::skip] // Becomes unreadable otherwise.
let tests: Vec<(_, &'static [u8])> = vec![
(vec![], &[]),
(vec![IoSlice::new(&[]), IoSlice::new(&[])], &[]),
(vec![IoSlice::new(&[1])], &[1]),
(vec![IoSlice::new(&[1, 2])], &[1, 2]),
(vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]),