@@ -538,32 +538,45 @@ fn test_rounding() {
538
538
assert_eq ! ( round_up_to_next( 5 , 4 ) , 8 ) ;
539
539
}
540
540
541
- // Returns a tuple of (minimum required malloc alignment, hash_offset,
542
- // key_offset, val_offset, array_size), from the start of a mallocated array.
543
- fn calculate_offsets (
544
- hash_size : uint , hash_align : uint ,
545
- keys_size : uint , keys_align : uint ,
546
- vals_size : uint , vals_align : uint ) -> ( uint , uint , uint , uint , uint ) {
541
+ // Returns a tuple of (key_offset, val_offset),
542
+ // from the start of a mallocated array.
543
+ fn calculate_offsets ( hashes_size : uint ,
544
+ keys_size : uint , keys_align : uint ,
545
+ vals_align : uint )
546
+ -> ( uint , uint ) {
547
+ let keys_offset = round_up_to_next ( hashes_size, keys_align) ;
548
+ let end_of_keys = keys_offset + keys_size;
547
549
548
- let hash_offset = 0 ;
549
- let end_of_hashes = hash_offset + hash_size;
550
+ let vals_offset = round_up_to_next ( end_of_keys, vals_align) ;
550
551
551
- let keys_offset = round_up_to_next ( end_of_hashes , keys_align ) ;
552
- let end_of_keys = keys_offset + keys_size ;
552
+ ( keys_offset , vals_offset )
553
+ }
553
554
554
- let vals_offset = round_up_to_next ( end_of_keys, vals_align) ;
555
- let end_of_vals = vals_offset + vals_size;
555
+ // Returns a tuple of (minimum required malloc alignment, hash_offset,
556
+ // array_size), from the start of a mallocated array.
557
+ fn calculate_allocation ( hash_size : uint , hash_align : uint ,
558
+ keys_size : uint , keys_align : uint ,
559
+ vals_size : uint , vals_align : uint )
560
+ -> ( uint , uint , uint ) {
561
+ let hash_offset = 0 ;
562
+ let ( _, vals_offset) = calculate_offsets ( hash_size,
563
+ keys_size, keys_align,
564
+ vals_align) ;
565
+ let end_of_vals = vals_offset + vals_size;
556
566
557
567
let min_align = cmp:: max ( hash_align, cmp:: max ( keys_align, vals_align) ) ;
558
568
559
- ( min_align, hash_offset, keys_offset , vals_offset , end_of_vals)
569
+ ( min_align, hash_offset, end_of_vals)
560
570
}
561
571
562
572
#[ test]
563
573
fn test_offset_calculation ( ) {
564
- assert_eq ! ( calculate_offsets( 128 , 8 , 15 , 1 , 4 , 4 ) , ( 8 , 0 , 128 , 144 , 148 ) ) ;
565
- assert_eq ! ( calculate_offsets( 3 , 1 , 2 , 1 , 1 , 1 ) , ( 1 , 0 , 3 , 5 , 6 ) ) ;
566
- assert_eq ! ( calculate_offsets( 6 , 2 , 12 , 4 , 24 , 8 ) , ( 8 , 0 , 8 , 24 , 48 ) ) ;
574
+ assert_eq ! ( calculate_allocation( 128 , 8 , 15 , 1 , 4 , 4 ) , ( 8 , 0 , 148 ) ) ;
575
+ assert_eq ! ( calculate_allocation( 3 , 1 , 2 , 1 , 1 , 1 ) , ( 1 , 0 , 6 ) ) ;
576
+ assert_eq ! ( calculate_allocation( 6 , 2 , 12 , 4 , 24 , 8 ) , ( 8 , 0 , 48 ) ) ;
577
+ assert_eq ! ( calculate_offsets( 128 , 15 , 1 , 4 ) , ( 128 , 144 ) ) ;
578
+ assert_eq ! ( calculate_offsets( 3 , 2 , 1 , 1 ) , ( 3 , 5 ) ) ;
579
+ assert_eq ! ( calculate_offsets( 6 , 12 , 4 , 8 ) , ( 8 , 24 ) ) ;
567
580
}
568
581
569
582
impl < K , V > RawTable < K , V > {
@@ -577,12 +590,11 @@ impl<K, V> RawTable<K, V> {
577
590
hashes : 0 as * mut u64 ,
578
591
} ;
579
592
}
580
- let hashes_size = capacity. checked_mul ( & size_of :: < u64 > ( ) )
581
- . expect ( "capacity overflow" ) ;
582
- let keys_size = capacity. checked_mul ( & size_of :: < K > ( ) )
583
- . expect ( "capacity overflow" ) ;
584
- let vals_size = capacity. checked_mul ( & size_of :: < V > ( ) )
585
- . expect ( "capacity overflow" ) ;
593
+ // No need for `checked_mul` before a more restrictive check performed
594
+ // later in this method.
595
+ let hashes_size = capacity * size_of :: < u64 > ( ) ;
596
+ let keys_size = capacity * size_of :: < K > ( ) ;
597
+ let vals_size = capacity * size_of :: < V > ( ) ;
586
598
587
599
// Allocating hashmaps is a little tricky. We need to allocate three
588
600
// arrays, but since we know their sizes and alignments up front,
@@ -592,12 +604,19 @@ impl<K, V> RawTable<K, V> {
592
604
// This is great in theory, but in practice getting the alignment
593
605
// right is a little subtle. Therefore, calculating offsets has been
594
606
// factored out into a different function.
595
- let ( malloc_alignment, hash_offset, _ , _ , size) =
596
- calculate_offsets (
607
+ let ( malloc_alignment, hash_offset, size) =
608
+ calculate_allocation (
597
609
hashes_size, min_align_of :: < u64 > ( ) ,
598
610
keys_size, min_align_of :: < K > ( ) ,
599
611
vals_size, min_align_of :: < V > ( ) ) ;
600
612
613
+ // One check for overflow that covers calculation and rounding of size.
614
+ let size_of_bucket = size_of :: < u64 > ( ) . checked_add ( & size_of :: < K > ( ) ) . unwrap ( )
615
+ . checked_add ( & size_of :: < V > ( ) ) . unwrap ( ) ;
616
+ assert ! ( size >= capacity. checked_mul( & size_of_bucket)
617
+ . expect( "capacity overflow" ) ,
618
+ "capacity overflow" ) ;
619
+
601
620
let buffer = allocate ( size, malloc_alignment) ;
602
621
603
622
let hashes = buffer. offset ( hash_offset as int ) as * mut u64 ;
@@ -613,12 +632,10 @@ impl<K, V> RawTable<K, V> {
613
632
let hashes_size = self . capacity * size_of :: < u64 > ( ) ;
614
633
let keys_size = self . capacity * size_of :: < K > ( ) ;
615
634
616
- let keys_offset = ( hashes_size + min_align_of :: < K > ( ) - 1 ) & !( min_align_of :: < K > ( ) - 1 ) ;
617
- let end_of_keys = keys_offset + keys_size;
618
-
619
- let vals_offset = ( end_of_keys + min_align_of :: < V > ( ) - 1 ) & !( min_align_of :: < V > ( ) - 1 ) ;
620
-
621
635
let buffer = self . hashes as * mut u8 ;
636
+ let ( keys_offset, vals_offset) = calculate_offsets ( hashes_size,
637
+ keys_size, min_align_of :: < K > ( ) ,
638
+ min_align_of :: < V > ( ) ) ;
622
639
623
640
unsafe {
624
641
RawBucket {
@@ -892,9 +909,9 @@ impl<K, V> Drop for RawTable<K, V> {
892
909
let hashes_size = self . capacity * size_of :: < u64 > ( ) ;
893
910
let keys_size = self . capacity * size_of :: < K > ( ) ;
894
911
let vals_size = self . capacity * size_of :: < V > ( ) ;
895
- let ( align, _, _ , _ , size) = calculate_offsets ( hashes_size, min_align_of :: < u64 > ( ) ,
896
- keys_size, min_align_of :: < K > ( ) ,
897
- vals_size, min_align_of :: < V > ( ) ) ;
912
+ let ( align, _, size) = calculate_allocation ( hashes_size, min_align_of :: < u64 > ( ) ,
913
+ keys_size, min_align_of :: < K > ( ) ,
914
+ vals_size, min_align_of :: < V > ( ) ) ;
898
915
899
916
unsafe {
900
917
deallocate ( self . hashes as * mut u8 , size, align) ;
0 commit comments