@@ -526,32 +526,45 @@ fn test_rounding() {
526526 assert_eq ! ( round_up_to_next( 5 , 4 ) , 8 ) ;
527527}
528528
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;
535537
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) ;
538539
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+ }
541542
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;
544554
545555 let min_align = cmp:: max ( hash_align, cmp:: max ( keys_align, vals_align) ) ;
546556
547- ( min_align, hash_offset, keys_offset , vals_offset , end_of_vals)
557+ ( min_align, hash_offset, end_of_vals)
548558}
549559
550560#[ test]
551561fn 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 ) ) ;
555568}
556569
557570impl < K , V > RawTable < K , V > {
@@ -566,12 +579,11 @@ impl<K, V> RawTable<K, V> {
566579 marker : marker:: CovariantType ,
567580 } ;
568581 }
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 > ( ) ;
575587
576588 // Allocating hashmaps is a little tricky. We need to allocate three
577589 // arrays, but since we know their sizes and alignments up front,
@@ -581,12 +593,19 @@ impl<K, V> RawTable<K, V> {
581593 // This is great in theory, but in practice getting the alignment
582594 // right is a little subtle. Therefore, calculating offsets has been
583595 // 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 (
586598 hashes_size, min_align_of :: < u64 > ( ) ,
587599 keys_size, min_align_of :: < K > ( ) ,
588600 vals_size, min_align_of :: < V > ( ) ) ;
589601
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+
590609 let buffer = allocate ( size, malloc_alignment) ;
591610
592611 let hashes = buffer. offset ( hash_offset as int ) as * mut u64 ;
@@ -603,12 +622,10 @@ impl<K, V> RawTable<K, V> {
603622 let hashes_size = self . capacity * size_of :: < u64 > ( ) ;
604623 let keys_size = self . capacity * size_of :: < K > ( ) ;
605624
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-
611625 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 > ( ) ) ;
612629
613630 unsafe {
614631 RawBucket {
@@ -866,9 +883,9 @@ impl<K, V> Drop for RawTable<K, V> {
866883 let hashes_size = self . capacity * size_of :: < u64 > ( ) ;
867884 let keys_size = self . capacity * size_of :: < K > ( ) ;
868885 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 > ( ) ) ;
872889
873890 unsafe {
874891 deallocate ( self . hashes as * mut u8 , size, align) ;
0 commit comments