diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 61c3913361717..e03aab1cc8fa1 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -254,7 +254,8 @@ pub fn read>(path: P) -> io::Result> { fn inner(path: &Path) -> io::Result> { let mut file = File::open(path)?; let size = file.metadata().map(|m| m.len() as usize).ok(); - let mut bytes = Vec::with_capacity(size.unwrap_or(0)); + let mut bytes = Vec::new(); + bytes.try_reserve(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?; io::default_read_to_end(&mut file, &mut bytes, size)?; Ok(bytes) } @@ -296,7 +297,8 @@ pub fn read_to_string>(path: P) -> io::Result { fn inner(path: &Path) -> io::Result { let mut file = File::open(path)?; let size = file.metadata().map(|m| m.len() as usize).ok(); - let mut string = String::with_capacity(size.unwrap_or(0)); + let mut string = String::new(); + string.try_reserve(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?; io::default_read_to_string(&mut file, &mut string, size)?; Ok(string) } @@ -770,14 +772,14 @@ impl Read for &File { // Reserves space in the buffer based on the file size when available. fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { let size = buffer_capacity_required(self); - buf.reserve(size.unwrap_or(0)); + buf.try_reserve(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?; io::default_read_to_end(self, buf, size) } // Reserves space in the buffer based on the file size when available. fn read_to_string(&mut self, buf: &mut String) -> io::Result { let size = buffer_capacity_required(self); - buf.reserve(size.unwrap_or(0)); + buf.try_reserve(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?; io::default_read_to_string(self, buf, size) } } diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 55aafc3db330a..75b7d5db071be 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -345,6 +345,7 @@ impl Read for BufReader { // delegate to the inner implementation. fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { let inner_buf = self.buffer(); + buf.try_reserve(inner_buf.len()).map_err(|_| io::ErrorKind::OutOfMemory)?; buf.extend_from_slice(inner_buf); let nread = inner_buf.len(); self.discard_buffer(); diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index aa9a2482d2d92..2b0f1f22349c2 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -419,7 +419,8 @@ pub(crate) fn default_read_to_end( let mut initialized = 0; // Extra initialized bytes from previous loop iteration loop { if buf.len() == buf.capacity() { - buf.reserve(32); // buf is full, need more space + // buf is full, need more space + buf.try_reserve(32).map_err(|_| ErrorKind::OutOfMemory)?; } let mut spare = buf.spare_capacity_mut(); @@ -465,6 +466,7 @@ pub(crate) fn default_read_to_end( match r.read(&mut probe) { Ok(0) => return Ok(buf.len() - start_len), Ok(n) => { + buf.try_reserve(n).map_err(|_| ErrorKind::OutOfMemory)?; buf.extend_from_slice(&probe[..n]); break; } @@ -768,6 +770,30 @@ pub trait Read { /// file.) /// /// [`std::fs::read`]: crate::fs::read + /// + /// ## Implementing `read_to_end` + /// + /// When implementing the `io::Read` trait, it is recommended to allocate + /// memory using [`Vec::try_reserve`]. However, this behavior is not guaranteed + /// by all implementations, and `read_to_end` may not handle out-of-memory + /// situations gracefully. + /// + /// ```no_run + /// # use std::io; + /// # struct Example; impl Example { + /// # fn read_some_data_for_the_example(&self) -> &'static [u8] { &[] } + /// fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + /// let data_read = self.read_some_data_for_the_example(); + /// + /// buf.try_reserve(data_read.len()).map_err(|_| io::ErrorKind::OutOfMemory)?; + /// buf.extend_from_slice(data_read); + /// + /// Ok(data_read.len()) + /// } + /// # } + /// ``` + /// + /// [`Vec::try_reserve`]: crate::vec::Vec::try_reserve #[stable(feature = "rust1", since = "1.0.0")] fn read_to_end(&mut self, buf: &mut Vec) -> Result { default_read_to_end(self, buf, None)