|
1 | 1 | #![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")]
|
2 | 2 |
|
3 | 3 | use core::alloc::LayoutError;
|
| 4 | +use core::cmp; |
4 | 5 | use core::intrinsics;
|
5 | 6 | use core::mem::{self, ManuallyDrop, MaybeUninit};
|
6 | 7 | use core::ops::Drop;
|
@@ -393,24 +394,32 @@ impl<T, A: Allocator> RawVec<T, A> {
|
393 | 394 | // Nothing we can really do about these checks, sadly.
|
394 | 395 | let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
|
395 | 396 |
|
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 | + }; |
414 | 423 |
|
415 | 424 | let new_layout = Layout::array::<T>(cap);
|
416 | 425 |
|
|
0 commit comments