Skip to content

Commit f016ed7

Browse files
committed
Handle out of memory errors in io:Read::read_to_end()
1 parent fb4bca0 commit f016ed7

File tree

4 files changed

+32
-5
lines changed

4 files changed

+32
-5
lines changed

library/std/src/fs.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -774,14 +774,14 @@ impl Read for &File {
774774
// Reserves space in the buffer based on the file size when available.
775775
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
776776
let size = buffer_capacity_required(self);
777-
buf.reserve(size.unwrap_or(0));
777+
buf.try_reserve(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
778778
io::default_read_to_end(self, buf, size)
779779
}
780780

781781
// Reserves space in the buffer based on the file size when available.
782782
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
783783
let size = buffer_capacity_required(self);
784-
buf.reserve(size.unwrap_or(0));
784+
buf.try_reserve(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
785785
io::default_read_to_string(self, buf, size)
786786
}
787787
}

library/std/src/io/buffered/bufreader.rs

+1
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ impl<R: ?Sized + Read> Read for BufReader<R> {
345345
// delegate to the inner implementation.
346346
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
347347
let inner_buf = self.buffer();
348+
buf.try_reserve(inner_buf.len()).map_err(|_| io::ErrorKind::OutOfMemory)?;
348349
buf.extend_from_slice(inner_buf);
349350
let nread = inner_buf.len();
350351
self.discard_buffer();

library/std/src/io/impls.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,9 @@ impl Read for &[u8] {
303303

304304
#[inline]
305305
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
306-
buf.extend_from_slice(*self);
307306
let len = self.len();
307+
buf.try_reserve(len).map_err(|_| ErrorKind::OutOfMemory)?;
308+
buf.extend_from_slice(*self);
308309
*self = &self[len..];
309310
Ok(len)
310311
}
@@ -451,7 +452,7 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
451452
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
452453
// The total len is known upfront so we can reserve it in a single call.
453454
let len = self.len();
454-
buf.reserve(len);
455+
buf.try_reserve(len).map_err(|_| ErrorKind::OutOfMemory)?;
455456

456457
let (front, back) = self.as_slices();
457458
buf.extend_from_slice(front);

library/std/src/io/mod.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,8 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
462462
}
463463

464464
if buf.len() == buf.capacity() {
465-
buf.reserve(PROBE_SIZE); // buf is full, need more space
465+
// buf is full, need more space
466+
buf.try_reserve(PROBE_SIZE).map_err(|_| ErrorKind::OutOfMemory)?;
466467
}
467468

468469
let mut spare = buf.spare_capacity_mut();
@@ -815,6 +816,30 @@ pub trait Read {
815816
/// file.)
816817
///
817818
/// [`std::fs::read`]: crate::fs::read
819+
///
820+
/// ## Implementing `read_to_end`
821+
///
822+
/// When implementing the `io::Read` trait, it is recommended to allocate
823+
/// memory using [`Vec::try_reserve`]. However, this behavior is not guaranteed
824+
/// by all implementations, and `read_to_end` may not handle out-of-memory
825+
/// situations gracefully.
826+
///
827+
/// ```no_run
828+
/// # use std::io;
829+
/// # struct Example; impl Example {
830+
/// # fn read_some_data_for_the_example(&self) -> &'static [u8] { &[] }
831+
/// fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
832+
/// let data_read = self.read_some_data_for_the_example();
833+
///
834+
/// buf.try_reserve(data_read.len()).map_err(|_| io::ErrorKind::OutOfMemory)?;
835+
/// buf.extend_from_slice(data_read);
836+
///
837+
/// Ok(data_read.len())
838+
/// }
839+
/// # }
840+
/// ```
841+
///
842+
/// [`Vec::try_reserve`]: crate::vec::Vec::try_reserve
818843
#[stable(feature = "rust1", since = "1.0.0")]
819844
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
820845
default_read_to_end(self, buf, None)

0 commit comments

Comments
 (0)