Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std::io: vectored reads with uninitialized memory (Read::read_buf_vec) #101842

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion library/std/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ mod tests;

use crate::ffi::OsString;
use crate::fmt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
use crate::io::{
self, BorrowedCursor, BorrowedSliceCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write,
};
use crate::path::{Path, PathBuf};
use crate::sys::fs as fs_imp;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
Expand Down Expand Up @@ -736,6 +738,10 @@ impl Read for File {
self.inner.read_buf(cursor)
}

fn read_buf_vectored(&mut self, cursor: BorrowedSliceCursor<'_>) -> io::Result<()> {
self.inner.read_buf_vectored(cursor)
}

#[inline]
fn is_read_vectored(&self) -> bool {
self.inner.is_read_vectored()
Expand Down Expand Up @@ -792,6 +798,10 @@ impl Read for &File {
self.inner.read_vectored(bufs)
}

fn read_buf_vectored(&mut self, cursor: BorrowedSliceCursor<'_>) -> io::Result<()> {
self.inner.read_buf_vectored(cursor)
}

#[inline]
fn is_read_vectored(&self) -> bool {
self.inner.is_read_vectored()
Expand Down
19 changes: 18 additions & 1 deletion library/std/src/io/buffered/bufreader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ mod buffer;

use crate::fmt;
use crate::io::{
self, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
self, BorrowedCursor, BorrowedSliceCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom, SizeHint,
DEFAULT_BUF_SIZE,
};
use buffer::Buffer;

Expand Down Expand Up @@ -311,6 +312,22 @@ impl<R: Read> Read for BufReader<R> {
Ok(nread)
}

fn read_buf_vectored(&mut self, mut cursor: BorrowedSliceCursor<'_>) -> io::Result<()> {
if self.buf.pos() == self.buf.filled() && cursor.capacity() >= self.capacity() {
self.discard_buffer();
return self.inner.read_buf_vectored(cursor);
}

let prev = cursor.written();

let mut rem = self.fill_buf()?;
rem.read_buf_vectored(cursor.reborrow())?;

self.consume(cursor.written() - prev);

Ok(())
}

fn is_read_vectored(&self) -> bool {
self.inner.is_read_vectored()
}
Expand Down
28 changes: 27 additions & 1 deletion library/std/src/io/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use crate::io::prelude::*;

use crate::alloc::Allocator;
use crate::cmp;
use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
use crate::io::{
self, BorrowedBuf, BorrowedCursor, BorrowedSliceCursor, ErrorKind, IoSlice, IoSliceMut,
SeekFrom,
};

/// A `Cursor` wraps an in-memory buffer and provides it with a
/// [`Seek`] implementation.
Expand Down Expand Up @@ -345,6 +348,29 @@ where
Ok(nread)
}

fn read_buf_vectored(&mut self, mut cursor: BorrowedSliceCursor<'_>) -> io::Result<()> {
let mut nread = 0;
while let Some(slice) = unsafe { cursor.next_mut() } {
let mut buf: BorrowedBuf<'_> = slice.into();
let mut cursor = buf.unfilled();
Read::read_buf(&mut self.fill_buf()?, cursor.reborrow())?;

let n = cursor.written();
self.pos += n as u64;
nread += n;

if n < slice.len() {
break;
}
}

unsafe {
cursor.advance(nread);
}

Ok(())
}

fn is_read_vectored(&self) -> bool {
true
}
Expand Down
24 changes: 23 additions & 1 deletion library/std/src/io/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use crate::cmp;
use crate::collections::VecDeque;
use crate::fmt;
use crate::io::{
self, BorrowedCursor, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write,
self, BorrowedCursor, BorrowedSliceCursor, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, Seek,
SeekFrom, Write,
};
use crate::mem;

Expand All @@ -30,6 +31,11 @@ impl<R: Read + ?Sized> Read for &mut R {
(**self).read_vectored(bufs)
}

#[inline]
fn read_buf_vectored(&mut self, cursor: BorrowedSliceCursor<'_>) -> io::Result<()> {
(**self).read_buf_vectored(cursor)
}

#[inline]
fn is_read_vectored(&self) -> bool {
(**self).is_read_vectored()
Expand Down Expand Up @@ -134,6 +140,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
(**self).read_vectored(bufs)
}

#[inline]
fn read_buf_vectored(&mut self, cursor: BorrowedSliceCursor<'_>) -> io::Result<()> {
(**self).read_buf_vectored(cursor)
}

#[inline]
fn is_read_vectored(&self) -> bool {
(**self).is_read_vectored()
Expand Down Expand Up @@ -272,6 +283,17 @@ impl Read for &[u8] {
Ok(nread)
}

#[inline]
fn read_buf_vectored(&mut self, mut cursor: BorrowedSliceCursor<'_>) -> io::Result<()> {
let amt = cmp::min(cursor.capacity(), self.len());
let (a, b) = self.split_at(amt);

cursor.append(a);

*self = b;
Ok(())
}

#[inline]
fn is_read_vectored(&self) -> bool {
true
Expand Down
31 changes: 30 additions & 1 deletion library/std/src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,9 @@ pub use self::{
};

#[unstable(feature = "read_buf", issue = "78485")]
pub use self::readbuf::{BorrowedBuf, BorrowedCursor};
pub use self::readbuf::{
BorrowedBuf, BorrowedCursor, BorrowedSliceBuf, BorrowedSliceCursor, IoSliceMaybeUninit,
};
pub(crate) use error::const_io_error;

mod buffered;
Expand Down Expand Up @@ -474,6 +476,27 @@ where
Ok(())
}

pub(crate) fn default_read_buf_vectored<F>(
read: F,
mut cursors: BorrowedSliceCursor<'_>,
) -> Result<()>
where
F: FnOnce(&mut [u8]) -> Result<usize>,
{
cursors.ensure_next_init();
if let Some(buf) = cursors.next_init_mut() {
let n = read(buf)?;
unsafe {
// SAFETY: we initialised using `ensure_init` so there is no uninit data to advance to.
cursors.advance(n);
}
} else {
read(&mut [])?;
}

Ok(())
}

/// The `Read` trait allows for reading bytes from a source.
///
/// Implementors of the `Read` trait are called 'readers'.
Expand Down Expand Up @@ -838,6 +861,12 @@ pub trait Read {
Ok(())
}

/// TODO docs
#[unstable(feature = "read_buf", issue = "78485")]
fn read_buf_vectored(&mut self, bufs: BorrowedSliceCursor<'_>) -> Result<()> {
default_read_buf_vectored(|b| self.read(b), bufs)
}

/// Creates a "by reference" adaptor for this instance of `Read`.
///
/// The returned adapter also implements `Read` and will simply borrow this
Expand Down
Loading