Skip to content

Commit 189e8c9

Browse files
committed
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.
1 parent 547369d commit 189e8c9

File tree

5 files changed

+47
-5
lines changed

5 files changed

+47
-5
lines changed

library/alloc/src/raw_vec.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,6 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
513513
// ensure that the code generation related to these panics is minimal as there's
514514
// only one location which panics rather than a bunch throughout the module.
515515
#[cfg(not(no_global_oom_handling))]
516-
fn capacity_overflow() -> ! {
516+
pub(crate) fn capacity_overflow() -> ! {
517517
panic!("capacity overflow");
518518
}

library/alloc/src/rc.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,9 @@ impl<T: ?Sized> Rc<T> {
12911291
// `&*(ptr as *const RcBox<T>)`, but this created a misaligned
12921292
// reference (see #54908).
12931293
let layout = Layout::new::<RcBox<()>>().extend(value_layout).unwrap().0.pad_to_align();
1294+
if layout.size() > isize::MAX as usize {
1295+
crate::raw_vec::capacity_overflow();
1296+
}
12941297
unsafe {
12951298
Rc::try_allocate_for_layout(value_layout, allocate, mem_to_rcbox)
12961299
.unwrap_or_else(|_| handle_alloc_error(layout))
@@ -1314,7 +1317,9 @@ impl<T: ?Sized> Rc<T> {
13141317
// `&*(ptr as *const RcBox<T>)`, but this created a misaligned
13151318
// reference (see #54908).
13161319
let layout = Layout::new::<RcBox<()>>().extend(value_layout).unwrap().0.pad_to_align();
1317-
1320+
if layout.size() > isize::MAX as usize {
1321+
return Err(AllocError);
1322+
}
13181323
// Allocate for the layout.
13191324
let ptr = allocate(layout)?;
13201325

@@ -2050,7 +2055,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I {
20502055
// length exceeding `usize::MAX`.
20512056
// The default implementation would collect into a vec which would panic.
20522057
// Thus we panic here immediately without invoking `Vec` code.
2053-
panic!("capacity overflow");
2058+
crate::raw_vec::capacity_overflow();
20542059
}
20552060
}
20562061
}

library/alloc/src/rc/tests.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::*;
2+
use core::mem::MaybeUninit;
23

34
use std::boxed::Box;
45
use std::cell::RefCell;
@@ -462,6 +463,21 @@ fn test_from_vec() {
462463
assert_eq!(&r[..], [1, 2, 3]);
463464
}
464465

466+
#[test]
467+
#[should_panic]
468+
fn test_uninit_slice_max_allocation() {
469+
let _: Rc<[MaybeUninit<u8>]> = Rc::new_uninit_slice(isize::MAX as usize);
470+
}
471+
472+
#[test]
473+
#[should_panic]
474+
fn test_from_iter_max_allocation() {
475+
// isize::MAX is the max allocation size
476+
// but due to the internal RcBox overhead the actual allocation will be larger and thus panic
477+
let len = isize::MAX as usize;
478+
let _ = (0..len).map(|_| MaybeUninit::<u8>::uninit()).collect::<Rc<[_]>>();
479+
}
480+
465481
#[test]
466482
fn test_downcast() {
467483
use std::any::Any;

library/alloc/src/sync.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,9 @@ impl<T: ?Sized> Arc<T> {
11371137
// `&*(ptr as *const ArcInner<T>)`, but this created a misaligned
11381138
// reference (see #54908).
11391139
let layout = Layout::new::<ArcInner<()>>().extend(value_layout).unwrap().0.pad_to_align();
1140+
if layout.size() > isize::MAX as usize {
1141+
crate::raw_vec::capacity_overflow();
1142+
}
11401143
unsafe {
11411144
Arc::try_allocate_for_layout(value_layout, allocate, mem_to_arcinner)
11421145
.unwrap_or_else(|_| handle_alloc_error(layout))
@@ -1159,7 +1162,9 @@ impl<T: ?Sized> Arc<T> {
11591162
// `&*(ptr as *const ArcInner<T>)`, but this created a misaligned
11601163
// reference (see #54908).
11611164
let layout = Layout::new::<ArcInner<()>>().extend(value_layout).unwrap().0.pad_to_align();
1162-
1165+
if layout.size() > isize::MAX as usize {
1166+
return Err(AllocError);
1167+
}
11631168
let ptr = allocate(layout)?;
11641169

11651170
// Initialize the ArcInner
@@ -2648,7 +2653,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToArcSlice<T> for I {
26482653
// length exceeding `usize::MAX`.
26492654
// The default implementation would collect into a vec which would panic.
26502655
// Thus we panic here immediately without invoking `Vec` code.
2651-
panic!("capacity overflow");
2656+
crate::raw_vec::capacity_overflow();
26522657
}
26532658
}
26542659
}

library/alloc/src/sync/tests.rs

+16
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::boxed::Box;
44
use std::clone::Clone;
55
use std::convert::{From, TryInto};
66
use std::mem::drop;
7+
use std::mem::MaybeUninit;
78
use std::ops::Drop;
89
use std::option::Option::{self, None, Some};
910
use std::sync::atomic::{
@@ -520,6 +521,21 @@ fn test_from_vec() {
520521
assert_eq!(&r[..], [1, 2, 3]);
521522
}
522523

524+
#[test]
525+
#[should_panic]
526+
fn test_uninit_slice_max_allocation() {
527+
let _: Arc<[MaybeUninit<u8>]> = Arc::new_uninit_slice(isize::MAX as usize);
528+
}
529+
530+
#[test]
531+
#[should_panic]
532+
fn test_from_iter_max_allocation() {
533+
// isize::MAX is the max allocation size
534+
// but due to the internal RcBox overhead the actual allocation will be larger and thus panic
535+
let len = isize::MAX;
536+
let _ = (0..len).map(|_| MaybeUninit::<u8>::uninit()).collect::<Arc<[_]>>();
537+
}
538+
523539
#[test]
524540
fn test_downcast() {
525541
use std::any::Any;

0 commit comments

Comments
 (0)