@@ -99,6 +99,8 @@ impl<T> RawVec<T> {
99
99
heap:: EMPTY as * mut u8
100
100
} else {
101
101
let align = mem:: align_of :: < T > ( ) ;
102
+ // FIXME: we do not round up the capacity here, pending the
103
+ // discussion in #29931
102
104
let ptr = heap:: allocate ( alloc_size, align) ;
103
105
if ptr. is_null ( ) {
104
106
oom ( )
@@ -215,14 +217,13 @@ impl<T> RawVec<T> {
215
217
} else {
216
218
4
217
219
} ;
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) ;
219
222
( new_cap, ptr)
220
223
} else {
221
224
// Since we guarantee that we never allocate more than isize::MAX bytes,
222
225
// `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 ) ;
226
227
let ptr = heap:: reallocate ( self . ptr ( ) as * mut _ ,
227
228
self . cap * elem_size,
228
229
new_alloc_size,
@@ -278,8 +279,7 @@ impl<T> RawVec<T> {
278
279
279
280
// Nothing we can really do about these checks :(
280
281
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) ;
283
283
284
284
let ptr = if self . cap == 0 {
285
285
heap:: allocate ( new_alloc_size, align)
@@ -370,9 +370,7 @@ impl<T> RawVec<T> {
370
370
// `double_cap` guarantees exponential growth.
371
371
let new_cap = cmp:: max ( double_cap, required_cap) ;
372
372
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) ;
376
374
377
375
let ptr = if self . cap == 0 {
378
376
heap:: allocate ( new_alloc_size, align)
@@ -422,6 +420,9 @@ impl<T> RawVec<T> {
422
420
unsafe {
423
421
// Overflow check is unnecessary as the vector is already at
424
422
// 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
425
426
let ptr = heap:: reallocate ( self . ptr ( ) as * mut _ ,
426
427
self . cap * elem_size,
427
428
amount * elem_size,
@@ -475,7 +476,24 @@ impl<T> Drop for RawVec<T> {
475
476
}
476
477
}
477
478
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;
478
494
495
+ ( alloc_size, cap)
496
+ }
479
497
480
498
// We need to guarantee the following:
481
499
// * We don't ever allocate `> isize::MAX` byte-size objects
@@ -501,27 +519,29 @@ mod tests {
501
519
502
520
#[ test]
503
521
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
504
524
{
505
525
let mut v: RawVec < u32 > = RawVec :: new ( ) ;
506
526
// First `reserve` allocates like `reserve_exact`
507
527
v. reserve ( 0 , 9 ) ;
508
- assert_eq ! ( 9 , v. cap( ) ) ;
528
+ assert ! ( v . cap ( ) >= 9 && v. cap( ) <= 9 * 2 ) ;
509
529
}
510
530
511
531
{
512
532
let mut v: RawVec < u32 > = RawVec :: new ( ) ;
513
533
v. reserve ( 0 , 7 ) ;
514
- assert_eq ! ( 7 , v. cap( ) ) ;
534
+ assert ! ( v . cap ( ) >= 7 && v. cap( ) <= 7 * 2 ) ;
515
535
// 97 if more than double of 7, so `reserve` should work
516
536
// like `reserve_exact`.
517
537
v. reserve ( 7 , 90 ) ;
518
- assert_eq ! ( 97 , v. cap( ) ) ;
538
+ assert ! ( v . cap ( ) >= 97 && v. cap( ) <= 97 * 2 ) ;
519
539
}
520
540
521
541
{
522
542
let mut v: RawVec < u32 > = RawVec :: new ( ) ;
523
543
v. reserve ( 0 , 12 ) ;
524
- assert_eq ! ( 12 , v. cap( ) ) ;
544
+ assert ! ( v . cap ( ) >= 12 && v. cap( ) <= 12 * 2 ) ;
525
545
v. reserve ( 12 , 3 ) ;
526
546
// 3 is less than half of 12, so `reserve` must grow
527
547
// exponentially. At the time of writing this test grow
0 commit comments