@@ -99,6 +99,8 @@ impl<T> RawVec<T> {
9999 heap:: EMPTY as * mut u8
100100 } else {
101101 let align = mem:: align_of :: < T > ( ) ;
102+ // FIXME: we do not round up the capacity here, pending the
103+ // discussion in #29931
102104 let ptr = heap:: allocate ( alloc_size, align) ;
103105 if ptr. is_null ( ) {
104106 oom ( )
@@ -215,14 +217,13 @@ impl<T> RawVec<T> {
215217 } else {
216218 4
217219 } ;
218- let ptr = heap:: allocate ( new_cap * elem_size, align) ;
220+ let ( alloc_size, new_cap) = round_up_alloc_size :: < T > ( new_cap) ;
221+ let ptr = heap:: allocate ( alloc_size, align) ;
219222 ( new_cap, ptr)
220223 } else {
221224 // Since we guarantee that we never allocate more than isize::MAX bytes,
222225 // `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow
223- let new_cap = 2 * self . cap ;
224- let new_alloc_size = new_cap * elem_size;
225- alloc_guard ( new_alloc_size) ;
226+ let ( new_alloc_size, new_cap) = round_up_alloc_size :: < T > ( 2 * self . cap ) ;
226227 let ptr = heap:: reallocate ( self . ptr ( ) as * mut _ ,
227228 self . cap * elem_size,
228229 new_alloc_size,
@@ -278,8 +279,7 @@ impl<T> RawVec<T> {
278279
279280 // Nothing we can really do about these checks :(
280281 let new_cap = used_cap. checked_add ( needed_extra_cap) . expect ( "capacity overflow" ) ;
281- let new_alloc_size = new_cap. checked_mul ( elem_size) . expect ( "capacity overflow" ) ;
282- alloc_guard ( new_alloc_size) ;
282+ let ( new_alloc_size, new_cap) = round_up_alloc_size :: < T > ( new_cap) ;
283283
284284 let ptr = if self . cap == 0 {
285285 heap:: allocate ( new_alloc_size, align)
@@ -370,9 +370,7 @@ impl<T> RawVec<T> {
370370 // `double_cap` guarantees exponential growth.
371371 let new_cap = cmp:: max ( double_cap, required_cap) ;
372372
373- let new_alloc_size = new_cap. checked_mul ( elem_size) . expect ( "capacity overflow" ) ;
374- // FIXME: may crash and burn on over-reserve
375- alloc_guard ( new_alloc_size) ;
373+ let ( new_alloc_size, new_cap) = round_up_alloc_size :: < T > ( new_cap) ;
376374
377375 let ptr = if self . cap == 0 {
378376 heap:: allocate ( new_alloc_size, align)
@@ -422,6 +420,9 @@ impl<T> RawVec<T> {
422420 unsafe {
423421 // Overflow check is unnecessary as the vector is already at
424422 // least this large.
423+ // FIXME: pending the discussion in #29931, we do not round up
424+ // the capacity here, since it might break assumptions for
425+ // example in Vec::into_boxed_slice
425426 let ptr = heap:: reallocate ( self . ptr ( ) as * mut _ ,
426427 self . cap * elem_size,
427428 amount * elem_size,
@@ -475,7 +476,24 @@ impl<T> Drop for RawVec<T> {
475476 }
476477}
477478
479+ // The system allocator may actually give us more memory than we requested.
480+ // The allocator usually gives a power-of-two, so instead of asking the
481+ // allocator via `heap::usable_size` which would incur some overhead, we rather
482+ // round up the request ourselves to the nearest power-of-two
483+
484+ #[ inline]
485+ fn round_up_alloc_size < T > ( cap : usize ) -> ( usize , usize ) {
486+ let elem_size = mem:: size_of :: < T > ( ) ;
487+
488+ let alloc_size = cap. checked_mul ( elem_size)
489+ . and_then ( usize:: checked_next_power_of_two) . expect ( "capacity overflow" ) ;
490+ alloc_guard ( alloc_size) ;
491+
492+ let cap = alloc_size / elem_size;
493+ let alloc_size = cap * elem_size;
478494
495+ ( alloc_size, cap)
496+ }
479497
480498// We need to guarantee the following:
481499// * We don't ever allocate `> isize::MAX` byte-size objects
@@ -501,27 +519,29 @@ mod tests {
501519
502520 #[ test]
503521 fn reserve_does_not_overallocate ( ) {
522+ // NB: when rounding up allocation sizes, the cap is not exact
523+ // but uses the whole memory allocated by the system allocator
504524 {
505525 let mut v: RawVec < u32 > = RawVec :: new ( ) ;
506526 // First `reserve` allocates like `reserve_exact`
507527 v. reserve ( 0 , 9 ) ;
508- assert_eq ! ( 9 , v. cap( ) ) ;
528+ assert ! ( v . cap ( ) >= 9 && v. cap( ) <= 9 * 2 ) ;
509529 }
510530
511531 {
512532 let mut v: RawVec < u32 > = RawVec :: new ( ) ;
513533 v. reserve ( 0 , 7 ) ;
514- assert_eq ! ( 7 , v. cap( ) ) ;
534+ assert ! ( v . cap ( ) >= 7 && v. cap( ) <= 7 * 2 ) ;
515535 // 97 if more than double of 7, so `reserve` should work
516536 // like `reserve_exact`.
517537 v. reserve ( 7 , 90 ) ;
518- assert_eq ! ( 97 , v. cap( ) ) ;
538+ assert ! ( v . cap ( ) >= 97 && v. cap( ) <= 97 * 2 ) ;
519539 }
520540
521541 {
522542 let mut v: RawVec < u32 > = RawVec :: new ( ) ;
523543 v. reserve ( 0 , 12 ) ;
524- assert_eq ! ( 12 , v. cap( ) ) ;
544+ assert ! ( v . cap ( ) >= 12 && v. cap( ) <= 12 * 2 ) ;
525545 v. reserve ( 12 , 3 ) ;
526546 // 3 is less than half of 12, so `reserve` must grow
527547 // exponentially. At the time of writing this test grow
0 commit comments