@@ -92,7 +92,7 @@ fn align_up(a: usize, alignment: usize) -> usize {
9292}
9393
9494fn left_bits ( x : u32 ) -> u32 {
95- ( x << 1 ) | ( !( x << 1 ) + 1 )
95+ ( x << 1 ) | ( !( x << 1 ) ) . wrapping_add ( 1 )
9696}
9797
9898fn least_bit ( x : u32 ) -> u32 {
@@ -150,7 +150,23 @@ impl Dlmalloc {
150150
151151 // TODO: dox
152152 fn max_request ( & self ) -> usize {
153- ( !self . min_chunk_size ( ) + 1 ) << 2
153+ // min_sys_alloc_space: the largest `X` such that
154+ // pad_request(X - 1) -- minus 1, because requests of exactly
155+ // `max_request` will not be honored
156+ // + self.top_foot_size()
157+ // + self.malloc_alignment()
158+ // + DEFAULT_GRANULARITY
159+ // ==
160+ // usize::MAX
161+ let min_sys_alloc_space = (
162+ ( !0 - ( DEFAULT_GRANULARITY + self . top_foot_size ( ) + self . malloc_alignment ( ) ) + 1 )
163+ & !self . malloc_alignment ( )
164+ ) - self . chunk_overhead ( ) + 1 ;
165+
166+ cmp:: min (
167+ ( !self . min_chunk_size ( ) + 1 ) << 2 ,
168+ min_sys_alloc_space
169+ )
154170 }
155171
156172 fn pad_request ( & self , amt : usize ) -> usize {
@@ -334,6 +350,7 @@ impl Dlmalloc {
334350
335351 unsafe fn sys_alloc ( & mut self , size : usize ) -> * mut u8 {
336352 self . check_malloc_state ( ) ;
353+ // keep in sync with max_request
337354 let asize = align_up ( size + self . top_foot_size ( ) + self . malloc_alignment ( ) ,
338355 DEFAULT_GRANULARITY ) ;
339356
@@ -1751,3 +1768,44 @@ impl Segment {
17511768 ( * seg) . base . offset ( ( * seg) . size as isize )
17521769 }
17531770}
1771+
1772+ #[ cfg( test) ]
1773+ mod tests {
1774+ use super :: * ;
1775+
1776+ // Prime the allocator with some allocations such that there will be free
1777+ // chunks in the treemap
1778+ unsafe fn setup_treemap ( a : & mut Dlmalloc ) {
1779+ let large_request_size = NSMALLBINS * ( 1 << SMALLBIN_SHIFT ) ;
1780+ assert ! ( !a. is_small( large_request_size) ) ;
1781+ let large_request1 = a. malloc ( large_request_size) ;
1782+ assert_ne ! ( large_request1, ptr:: null_mut( ) ) ;
1783+ let large_request2 = a. malloc ( large_request_size) ;
1784+ assert_ne ! ( large_request2, ptr:: null_mut( ) ) ;
1785+ a. free ( large_request1) ;
1786+ assert_ne ! ( a. treemap, 0 ) ;
1787+ }
1788+
1789+ #[ test]
1790+ // Test allocating, with a non-empty treemap, a specific size that used to
1791+ // trigger an integer overflow bug
1792+ fn treemap_alloc_overflow_minimal ( ) {
1793+ let mut a = DLMALLOC_INIT ;
1794+ unsafe {
1795+ setup_treemap ( & mut a) ;
1796+ let min_idx31_size = ( 0xc000 << TREEBIN_SHIFT ) - a. chunk_overhead ( ) + 1 ;
1797+ assert_ne ! ( a. malloc( min_idx31_size) , ptr:: null_mut( ) ) ;
1798+ }
1799+ }
1800+
1801+ #[ test]
1802+ // Test allocating the maximum request size with a non-empty treemap
1803+ fn treemap_alloc_max ( ) {
1804+ let mut a = DLMALLOC_INIT ;
1805+ unsafe {
1806+ setup_treemap ( & mut a) ;
1807+ let max_request_size = a. max_request ( ) - 1 ;
1808+ assert_eq ! ( a. malloc( max_request_size) , ptr:: null_mut( ) ) ;
1809+ }
1810+ }
1811+ }
0 commit comments