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

Fix (A)Rc<[T]> slices larger than isize::MAX bytes when collecting from a TrustedLen iter #95252

Closed
wants to merge 1 commit 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
2 changes: 1 addition & 1 deletion library/alloc/src/raw_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
9 changes: 7 additions & 2 deletions library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,9 @@ impl<T: ?Sized> Rc<T> {
// `&*(ptr as *const RcBox<T>)`, but this created a misaligned
// reference (see #54908).
let layout = Layout::new::<RcBox<()>>().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))
Expand All @@ -1314,7 +1317,9 @@ impl<T: ?Sized> Rc<T> {
// `&*(ptr as *const RcBox<T>)`, but this created a misaligned
// reference (see #54908).
let layout = Layout::new::<RcBox<()>>().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)?;

Expand Down Expand Up @@ -2050,7 +2055,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> 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();
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions library/alloc/src/rc/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use core::mem::MaybeUninit;

use std::boxed::Box;
use std::cell::RefCell;
Expand Down Expand Up @@ -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<u8>]> = 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::<u8>::uninit()).collect::<Rc<[_]>>();
}

#[test]
fn test_downcast() {
use std::any::Any;
Expand Down
9 changes: 7 additions & 2 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,9 @@ impl<T: ?Sized> Arc<T> {
// `&*(ptr as *const ArcInner<T>)`, but this created a misaligned
// reference (see #54908).
let layout = Layout::new::<ArcInner<()>>().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))
Expand All @@ -1159,7 +1162,9 @@ impl<T: ?Sized> Arc<T> {
// `&*(ptr as *const ArcInner<T>)`, but this created a misaligned
// reference (see #54908).
let layout = Layout::new::<ArcInner<()>>().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
Expand Down Expand Up @@ -2648,7 +2653,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToArcSlice<T> 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();
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions library/alloc/src/sync/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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<u8>]> = 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::<u8>::uninit()).collect::<Arc<[_]>>();
}

#[test]
fn test_downcast() {
use std::any::Any;
Expand Down