@@ -526,32 +526,45 @@ fn test_rounding() {
526
526
assert_eq ! ( round_up_to_next( 5 , 4 ) , 8 ) ;
527
527
}
528
528
529
- // Returns a tuple of (minimum required malloc alignment, hash_offset,
530
- // key_offset, val_offset, array_size), from the start of a mallocated array.
531
- fn calculate_offsets (
532
- hash_size : uint , hash_align : uint ,
533
- keys_size : uint , keys_align : uint ,
534
- vals_size : uint , vals_align : uint ) -> ( uint , uint , uint , uint , uint ) {
529
+ // Returns a tuple of (key_offset, val_offset),
530
+ // from the start of a mallocated array.
531
+ fn calculate_offsets ( hashes_size : uint ,
532
+ keys_size : uint , keys_align : uint ,
533
+ vals_align : uint )
534
+ -> ( uint , uint ) {
535
+ let keys_offset = round_up_to_next ( hashes_size, keys_align) ;
536
+ let end_of_keys = keys_offset + keys_size;
535
537
536
- let hash_offset = 0 ;
537
- let end_of_hashes = hash_offset + hash_size;
538
+ let vals_offset = round_up_to_next ( end_of_keys, vals_align) ;
538
539
539
- let keys_offset = round_up_to_next ( end_of_hashes , keys_align ) ;
540
- let end_of_keys = keys_offset + keys_size ;
540
+ ( keys_offset , vals_offset )
541
+ }
541
542
542
- let vals_offset = round_up_to_next ( end_of_keys, vals_align) ;
543
- let end_of_vals = vals_offset + vals_size;
543
+ // Returns a tuple of (minimum required malloc alignment, hash_offset,
544
+ // array_size), from the start of a mallocated array.
545
+ fn calculate_allocation ( hash_size : uint , hash_align : uint ,
546
+ keys_size : uint , keys_align : uint ,
547
+ vals_size : uint , vals_align : uint )
548
+ -> ( uint , uint , uint ) {
549
+ let hash_offset = 0 ;
550
+ let ( _, vals_offset) = calculate_offsets ( hash_size,
551
+ keys_size, keys_align,
552
+ vals_align) ;
553
+ let end_of_vals = vals_offset + vals_size;
544
554
545
555
let min_align = cmp:: max ( hash_align, cmp:: max ( keys_align, vals_align) ) ;
546
556
547
- ( min_align, hash_offset, keys_offset , vals_offset , end_of_vals)
557
+ ( min_align, hash_offset, end_of_vals)
548
558
}
549
559
550
560
#[ test]
551
561
fn test_offset_calculation ( ) {
552
- assert_eq ! ( calculate_offsets( 128 , 8 , 15 , 1 , 4 , 4 ) , ( 8 , 0 , 128 , 144 , 148 ) ) ;
553
- assert_eq ! ( calculate_offsets( 3 , 1 , 2 , 1 , 1 , 1 ) , ( 1 , 0 , 3 , 5 , 6 ) ) ;
554
- assert_eq ! ( calculate_offsets( 6 , 2 , 12 , 4 , 24 , 8 ) , ( 8 , 0 , 8 , 24 , 48 ) ) ;
562
+ assert_eq ! ( calculate_allocation( 128 , 8 , 15 , 1 , 4 , 4 ) , ( 8 , 0 , 148 ) ) ;
563
+ assert_eq ! ( calculate_allocation( 3 , 1 , 2 , 1 , 1 , 1 ) , ( 1 , 0 , 6 ) ) ;
564
+ assert_eq ! ( calculate_allocation( 6 , 2 , 12 , 4 , 24 , 8 ) , ( 8 , 0 , 48 ) ) ;
565
+ assert_eq ! ( calculate_offsets( 128 , 15 , 1 , 4 ) , ( 128 , 144 ) ) ;
566
+ assert_eq ! ( calculate_offsets( 3 , 2 , 1 , 1 ) , ( 3 , 5 ) ) ;
567
+ assert_eq ! ( calculate_offsets( 6 , 12 , 4 , 8 ) , ( 8 , 24 ) ) ;
555
568
}
556
569
557
570
impl < K , V > RawTable < K , V > {
@@ -566,12 +579,11 @@ impl<K, V> RawTable<K, V> {
566
579
marker : marker:: CovariantType ,
567
580
} ;
568
581
}
569
- let hashes_size = capacity. checked_mul ( & size_of :: < u64 > ( ) )
570
- . expect ( "capacity overflow" ) ;
571
- let keys_size = capacity. checked_mul ( & size_of :: < K > ( ) )
572
- . expect ( "capacity overflow" ) ;
573
- let vals_size = capacity. checked_mul ( & size_of :: < V > ( ) )
574
- . expect ( "capacity overflow" ) ;
582
+ // No need for `checked_mul` before a more restrictive check performed
583
+ // later in this method.
584
+ let hashes_size = capacity * size_of :: < u64 > ( ) ;
585
+ let keys_size = capacity * size_of :: < K > ( ) ;
586
+ let vals_size = capacity * size_of :: < V > ( ) ;
575
587
576
588
// Allocating hashmaps is a little tricky. We need to allocate three
577
589
// arrays, but since we know their sizes and alignments up front,
@@ -581,12 +593,19 @@ impl<K, V> RawTable<K, V> {
581
593
// This is great in theory, but in practice getting the alignment
582
594
// right is a little subtle. Therefore, calculating offsets has been
583
595
// factored out into a different function.
584
- let ( malloc_alignment, hash_offset, _ , _ , size) =
585
- calculate_offsets (
596
+ let ( malloc_alignment, hash_offset, size) =
597
+ calculate_allocation (
586
598
hashes_size, min_align_of :: < u64 > ( ) ,
587
599
keys_size, min_align_of :: < K > ( ) ,
588
600
vals_size, min_align_of :: < V > ( ) ) ;
589
601
602
+ // One check for overflow that covers calculation and rounding of size.
603
+ let size_of_bucket = size_of :: < u64 > ( ) . checked_add ( & size_of :: < K > ( ) ) . unwrap ( )
604
+ . checked_add ( & size_of :: < V > ( ) ) . unwrap ( ) ;
605
+ assert ! ( size >= capacity. checked_mul( & size_of_bucket)
606
+ . expect( "capacity overflow" ) ,
607
+ "capacity overflow" ) ;
608
+
590
609
let buffer = allocate ( size, malloc_alignment) ;
591
610
592
611
let hashes = buffer. offset ( hash_offset as int ) as * mut u64 ;
@@ -603,12 +622,10 @@ impl<K, V> RawTable<K, V> {
603
622
let hashes_size = self . capacity * size_of :: < u64 > ( ) ;
604
623
let keys_size = self . capacity * size_of :: < K > ( ) ;
605
624
606
- let keys_offset = ( hashes_size + min_align_of :: < K > ( ) - 1 ) & !( min_align_of :: < K > ( ) - 1 ) ;
607
- let end_of_keys = keys_offset + keys_size;
608
-
609
- let vals_offset = ( end_of_keys + min_align_of :: < V > ( ) - 1 ) & !( min_align_of :: < V > ( ) - 1 ) ;
610
-
611
625
let buffer = self . hashes as * mut u8 ;
626
+ let ( keys_offset, vals_offset) = calculate_offsets ( hashes_size,
627
+ keys_size, min_align_of :: < K > ( ) ,
628
+ min_align_of :: < V > ( ) ) ;
612
629
613
630
unsafe {
614
631
RawBucket {
@@ -866,9 +883,9 @@ impl<K, V> Drop for RawTable<K, V> {
866
883
let hashes_size = self . capacity * size_of :: < u64 > ( ) ;
867
884
let keys_size = self . capacity * size_of :: < K > ( ) ;
868
885
let vals_size = self . capacity * size_of :: < V > ( ) ;
869
- let ( align, _, _ , _ , size) = calculate_offsets ( hashes_size, min_align_of :: < u64 > ( ) ,
870
- keys_size, min_align_of :: < K > ( ) ,
871
- vals_size, min_align_of :: < V > ( ) ) ;
886
+ let ( align, _, size) = calculate_allocation ( hashes_size, min_align_of :: < u64 > ( ) ,
887
+ keys_size, min_align_of :: < K > ( ) ,
888
+ vals_size, min_align_of :: < V > ( ) ) ;
872
889
873
890
unsafe {
874
891
deallocate ( self . hashes as * mut u8 , size, align) ;
0 commit comments