@@ -92,7 +92,7 @@ fn align_up(a: usize, alignment: usize) -> usize {
92
92
}
93
93
94
94
fn left_bits ( x : u32 ) -> u32 {
95
- ( x << 1 ) | ( !( x << 1 ) + 1 )
95
+ ( x << 1 ) | ( !( x << 1 ) ) . wrapping_add ( 1 )
96
96
}
97
97
98
98
fn least_bit ( x : u32 ) -> u32 {
@@ -150,7 +150,23 @@ impl Dlmalloc {
150
150
151
151
// TODO: dox
152
152
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
+ )
154
170
}
155
171
156
172
fn pad_request ( & self , amt : usize ) -> usize {
@@ -334,6 +350,7 @@ impl Dlmalloc {
334
350
335
351
unsafe fn sys_alloc ( & mut self , size : usize ) -> * mut u8 {
336
352
self . check_malloc_state ( ) ;
353
+ // keep in sync with max_request
337
354
let asize = align_up ( size + self . top_foot_size ( ) + self . malloc_alignment ( ) ,
338
355
DEFAULT_GRANULARITY ) ;
339
356
@@ -1751,3 +1768,44 @@ impl Segment {
1751
1768
( * seg) . base . offset ( ( * seg) . size as isize )
1752
1769
}
1753
1770
}
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