Skip to content

Commit 36d064f

Browse files
committed
Fix overflows
1 parent dbc2ef8 commit 36d064f

File tree

1 file changed

+27
-18
lines changed

1 file changed

+27
-18
lines changed

library/alloc/src/raw_vec.rs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")]
22

33
use core::alloc::LayoutError;
4+
use core::cmp;
45
use core::intrinsics;
56
use core::mem::{self, ManuallyDrop, MaybeUninit};
67
use core::ops::Drop;
@@ -393,24 +394,32 @@ impl<T, A: Allocator> RawVec<T, A> {
393394
// Nothing we can really do about these checks, sadly.
394395
let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
395396

396-
let alloc_size = required_cap.checked_mul(mem::size_of::<T>()).ok_or(CapacityOverflow)?;
397-
// Add the overhead
398-
let alloc_size = alloc_size.checked_add(alloc_overhead_size).ok_or(CapacityOverflow)?;
399-
400-
// Since memory allocators tend to use power of two sized bins, find the
401-
// bin size we will fall into.
402-
debug_assert!(alloc_size > 1);
403-
let bin_size = usize::MAX >> (alloc_size - 1).leading_zeros(); // + 1 skipped to prevent overflow
404-
405-
// Leave some room for allocators that add fixed overhead (usually
406-
// one pointer-size)
407-
let aligned_alloc_size = bin_size.saturating_sub(alloc_overhead_size - 1) /* the +1 skipped from the previous line turned into -1 here */ ;
408-
409-
// Align the capacity to fit the bin
410-
let cap = aligned_alloc_size / mem::size_of::<T>();
411-
// Since we've added the overhead in `required_cap`, we shold never
412-
// end up with smaller cap after aligning
413-
debug_assert!(required_cap <= cap);
397+
let cap = if let Some(alloc_size) = required_cap
398+
.checked_mul(mem::size_of::<T>())
399+
.and_then(
400+
// Add the overhead
401+
|alloc_size| alloc_size.checked_add(alloc_overhead_size),
402+
)
403+
.filter(|alloc_size| *alloc_size < isize::MAX as usize)
404+
{
405+
// Since memory allocators tend to use power of two sized bins, find the
406+
// bin size we will fall into.
407+
debug_assert!(alloc_size > 1);
408+
let bin_size = usize::MAX >> (alloc_size - 1).leading_zeros(); // + 1 skipped to prevent overflow
409+
debug_assert!(alloc_size - 1 <= bin_size);
410+
411+
// Leave some room for allocators that add fixed overhead (usually
412+
// one pointer-size)
413+
// `bin_size - ...` can't underflow, because alloc_overhead_size was already added
414+
let aligned_alloc_size = bin_size - (alloc_overhead_size - 1) /* the +1 skipped from the previous line turned into -1 here */ ;
415+
416+
// Align the capacity to fit the bin
417+
aligned_alloc_size / mem::size_of::<T>()
418+
} else {
419+
// Calculating alloc_size overflowed. Use old way to preserve behavior around overflows.
420+
// The doubling cannot overflow because `cap <= isize::MAX` and the type of `cap` is `usize`.
421+
cmp::max(self.cap * 2, required_cap)
422+
};
414423

415424
let new_layout = Layout::array::<T>(cap);
416425

0 commit comments

Comments
 (0)