Skip to content

Commit 8d35fda

Browse files
authored
Unrolled build for rust-lang#121403
Rollup merge of rust-lang#121403 - kornelski:io-oom, r=dtolnay impl From<TryReserveError> for io::Error There's an obvious mapping between these two errors, and it makes I/O code less noisy. I've chosen to use simple `ErrorKind::OutOfMemory` `io::Error`, without keeping `TryReserveError` for the `source()`, because: * It matches current uses in libstd, * `ErrorData::Custom` allocates, which is a risky proposition for handling OOM errors specifically. * Currently `TryReserveError` has no public fields/methods, so it's usefulness is limited. How allocators should report errors, especially custom and verbose ones is still an open question. Just in case I've added note in the doccomment that this may change. The compiler forced me to declare stability of this impl. I think this implementation is simple enough that it doesn't need full-blown stabilization period, and I've marked it for the next release, but of course I can adjust the attribute if needed.
2 parents 25ee3c6 + aa581f0 commit 8d35fda

File tree

6 files changed

+31
-9
lines changed

6 files changed

+31
-9
lines changed

library/std/src/fs.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
261261
let mut file = File::open(path)?;
262262
let size = file.metadata().map(|m| m.len() as usize).ok();
263263
let mut bytes = Vec::new();
264-
bytes.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
264+
bytes.try_reserve_exact(size.unwrap_or(0))?;
265265
io::default_read_to_end(&mut file, &mut bytes, size)?;
266266
Ok(bytes)
267267
}
@@ -304,7 +304,7 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
304304
let mut file = File::open(path)?;
305305
let size = file.metadata().map(|m| m.len() as usize).ok();
306306
let mut string = String::new();
307-
string.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
307+
string.try_reserve_exact(size.unwrap_or(0))?;
308308
io::default_read_to_string(&mut file, &mut string, size)?;
309309
Ok(string)
310310
}
@@ -777,14 +777,14 @@ impl Read for &File {
777777
// Reserves space in the buffer based on the file size when available.
778778
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
779779
let size = buffer_capacity_required(self);
780-
buf.try_reserve(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
780+
buf.try_reserve(size.unwrap_or(0))?;
781781
io::default_read_to_end(self, buf, size)
782782
}
783783

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

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

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

library/std/src/io/error.rs

+12
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@ impl From<alloc::ffi::NulError> for Error {
8383
}
8484
}
8585

86+
#[stable(feature = "io_error_from_try_reserve", since = "CURRENT_RUSTC_VERSION")]
87+
impl From<alloc::collections::TryReserveError> for Error {
88+
/// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`].
89+
///
90+
/// `TryReserveError` won't be available as the error `source()`,
91+
/// but this may change in the future.
92+
fn from(_: alloc::collections::TryReserveError) -> Error {
93+
// ErrorData::Custom allocates, which isn't great for handling OOM errors.
94+
ErrorKind::OutOfMemory.into()
95+
}
96+
}
97+
8698
// Only derive debug in tests, to make sure it
8799
// doesn't accidentally get printed.
88100
#[cfg_attr(test, derive(Debug))]

library/std/src/io/impls.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ impl Read for &[u8] {
304304
#[inline]
305305
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
306306
let len = self.len();
307-
buf.try_reserve(len).map_err(|_| ErrorKind::OutOfMemory)?;
307+
buf.try_reserve(len)?;
308308
buf.extend_from_slice(*self);
309309
*self = &self[len..];
310310
Ok(len)
@@ -452,7 +452,7 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
452452
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
453453
// The total len is known upfront so we can reserve it in a single call.
454454
let len = self.len();
455-
buf.try_reserve(len).map_err(|_| ErrorKind::OutOfMemory)?;
455+
buf.try_reserve(len)?;
456456

457457
let (front, back) = self.as_slices();
458458
buf.extend_from_slice(front);

library/std/src/io/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
465465

466466
if buf.len() == buf.capacity() {
467467
// buf is full, need more space
468-
buf.try_reserve(PROBE_SIZE).map_err(|_| ErrorKind::OutOfMemory)?;
468+
buf.try_reserve(PROBE_SIZE)?;
469469
}
470470

471471
let mut spare = buf.spare_capacity_mut();
@@ -834,7 +834,7 @@ pub trait Read {
834834
/// if src_buf.is_empty() {
835835
/// break;
836836
/// }
837-
/// dest_vec.try_reserve(src_buf.len()).map_err(|_| io::ErrorKind::OutOfMemory)?;
837+
/// dest_vec.try_reserve(src_buf.len())?;
838838
/// dest_vec.extend_from_slice(src_buf);
839839
///
840840
/// // Any irreversible side effects should happen after `try_reserve` succeeds,

library/std/src/io/tests.rs

+10
Original file line numberDiff line numberDiff line change
@@ -692,3 +692,13 @@ fn read_buf_full_read() {
692692

693693
assert_eq!(BufReader::new(FullRead).fill_buf().unwrap().len(), DEFAULT_BUF_SIZE);
694694
}
695+
696+
#[test]
697+
// 64-bit only to be sure the allocator will fail fast on an impossible to satsify size
698+
#[cfg(target_pointer_width = "64")]
699+
fn try_oom_error() {
700+
let mut v = Vec::<u8>::new();
701+
let reserve_err = v.try_reserve(isize::MAX as usize - 1).unwrap_err();
702+
let io_err = io::Error::from(reserve_err);
703+
assert_eq!(io::ErrorKind::OutOfMemory, io_err.kind());
704+
}

0 commit comments

Comments
 (0)