From 189e8c9231204aa6ba9ef9df04bdaee6b5eb93b0 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 23 Mar 2022 23:11:45 +0100 Subject: [PATCH] Fix (A)Rc<[T]> trying to allocate RcBox larger than isize::MAX bytes Due to ptr::add restrictions allocations must be <= isize::MAX bytes. The default implementation goes through Vec which ensures this, but the uninit and TrustedLen code paths lack the necessary check. --- library/alloc/src/raw_vec.rs | 2 +- library/alloc/src/rc.rs | 9 +++++++-- library/alloc/src/rc/tests.rs | 16 ++++++++++++++++ library/alloc/src/sync.rs | 9 +++++++-- library/alloc/src/sync/tests.rs | 16 ++++++++++++++++ 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 0ce2beb63d681..d039f529eedec 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -513,6 +513,6 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { // ensure that the code generation related to these panics is minimal as there's // only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] -fn capacity_overflow() -> ! { +pub(crate) fn capacity_overflow() -> ! { panic!("capacity overflow"); } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index ea651c075d968..8d7f881c241c7 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1291,6 +1291,9 @@ impl Rc { // `&*(ptr as *const RcBox)`, but this created a misaligned // reference (see #54908). let layout = Layout::new::>().extend(value_layout).unwrap().0.pad_to_align(); + if layout.size() > isize::MAX as usize { + crate::raw_vec::capacity_overflow(); + } unsafe { Rc::try_allocate_for_layout(value_layout, allocate, mem_to_rcbox) .unwrap_or_else(|_| handle_alloc_error(layout)) @@ -1314,7 +1317,9 @@ impl Rc { // `&*(ptr as *const RcBox)`, but this created a misaligned // reference (see #54908). let layout = Layout::new::>().extend(value_layout).unwrap().0.pad_to_align(); - + if layout.size() > isize::MAX as usize { + return Err(AllocError); + } // Allocate for the layout. let ptr = allocate(layout)?; @@ -2050,7 +2055,7 @@ impl> ToRcSlice for I { // length exceeding `usize::MAX`. // The default implementation would collect into a vec which would panic. // Thus we panic here immediately without invoking `Vec` code. - panic!("capacity overflow"); + crate::raw_vec::capacity_overflow(); } } } diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index d7c28f8063337..5c423bcf6d6ac 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -1,4 +1,5 @@ use super::*; +use core::mem::MaybeUninit; use std::boxed::Box; use std::cell::RefCell; @@ -462,6 +463,21 @@ fn test_from_vec() { assert_eq!(&r[..], [1, 2, 3]); } +#[test] +#[should_panic] +fn test_uninit_slice_max_allocation() { + let _: Rc<[MaybeUninit]> = Rc::new_uninit_slice(isize::MAX as usize); +} + +#[test] +#[should_panic] +fn test_from_iter_max_allocation() { + // isize::MAX is the max allocation size + // but due to the internal RcBox overhead the actual allocation will be larger and thus panic + let len = isize::MAX as usize; + let _ = (0..len).map(|_| MaybeUninit::::uninit()).collect::>(); +} + #[test] fn test_downcast() { use std::any::Any; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index ba3187294e654..194b00443f275 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1137,6 +1137,9 @@ impl Arc { // `&*(ptr as *const ArcInner)`, but this created a misaligned // reference (see #54908). let layout = Layout::new::>().extend(value_layout).unwrap().0.pad_to_align(); + if layout.size() > isize::MAX as usize { + crate::raw_vec::capacity_overflow(); + } unsafe { Arc::try_allocate_for_layout(value_layout, allocate, mem_to_arcinner) .unwrap_or_else(|_| handle_alloc_error(layout)) @@ -1159,7 +1162,9 @@ impl Arc { // `&*(ptr as *const ArcInner)`, but this created a misaligned // reference (see #54908). let layout = Layout::new::>().extend(value_layout).unwrap().0.pad_to_align(); - + if layout.size() > isize::MAX as usize { + return Err(AllocError); + } let ptr = allocate(layout)?; // Initialize the ArcInner @@ -2648,7 +2653,7 @@ impl> ToArcSlice for I { // length exceeding `usize::MAX`. // The default implementation would collect into a vec which would panic. // Thus we panic here immediately without invoking `Vec` code. - panic!("capacity overflow"); + crate::raw_vec::capacity_overflow(); } } } diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index 452a88773018c..e77adf3f9b867 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -4,6 +4,7 @@ use std::boxed::Box; use std::clone::Clone; use std::convert::{From, TryInto}; use std::mem::drop; +use std::mem::MaybeUninit; use std::ops::Drop; use std::option::Option::{self, None, Some}; use std::sync::atomic::{ @@ -520,6 +521,21 @@ fn test_from_vec() { assert_eq!(&r[..], [1, 2, 3]); } +#[test] +#[should_panic] +fn test_uninit_slice_max_allocation() { + let _: Arc<[MaybeUninit]> = Arc::new_uninit_slice(isize::MAX as usize); +} + +#[test] +#[should_panic] +fn test_from_iter_max_allocation() { + // isize::MAX is the max allocation size + // but due to the internal RcBox overhead the actual allocation will be larger and thus panic + let len = isize::MAX; + let _ = (0..len).map(|_| MaybeUninit::::uninit()).collect::>(); +} + #[test] fn test_downcast() { use std::any::Any;