@@ -83,9 +83,7 @@ impl Cursor {
83
83
// it will just have a smaller size after we have chopped off the "tail" for
84
84
// the allocation.
85
85
addr : hole_addr_u8,
86
- size : unsafe { aligned_addr. offset_from ( hole_addr_u8) }
87
- . try_into ( )
88
- . unwrap ( ) ,
86
+ size : ( aligned_addr as usize ) - ( hole_addr_u8 as usize ) ,
89
87
} ) ;
90
88
aligned_addr
91
89
} ;
@@ -109,24 +107,25 @@ impl Cursor {
109
107
// sort of assume that the allocation is actually a bit larger than it
110
108
// actually needs to be.
111
109
//
112
- // TODO(AJM): Write a test for this - does the code actually handle this
113
- // correctly? Do we need to check the delta is less than an aligned hole
114
- // size?
110
+ // NOTE: Because we always use `HoleList::align_layout`, the size of
111
+ // the new allocation is always "rounded up" to cover any partial gaps that
112
+ // would have occurred. For this reason, we DON'T need to "round up"
113
+ // to account for an unaligned hole spot.
115
114
let hole_layout = Layout :: new :: < Hole > ( ) ;
116
115
let back_padding_start = align_up ( allocation_end, hole_layout. align ( ) ) ;
117
116
let back_padding_end = back_padding_start. wrapping_add ( hole_layout. size ( ) ) ;
118
117
119
118
// Will the proposed new back padding actually fit in the old hole slot?
120
119
back_padding = if back_padding_end <= hole_end {
121
- // Yes, it does!
120
+ // Yes, it does! Place a back padding node
122
121
Some ( HoleInfo {
123
122
addr : back_padding_start,
124
- size : unsafe { hole_end. offset_from ( back_padding_start) }
125
- . try_into ( )
126
- . unwrap ( ) ,
123
+ size : ( hole_end as usize ) - ( back_padding_start as usize ) ,
127
124
} )
128
125
} else {
129
- // No, it does not.
126
+ // No, it does not. We are now pretending the allocation now
127
+ // holds the extra 0..size_of::<Hole>() bytes that are not
128
+ // big enough to hold what SHOULD be back_padding
130
129
None
131
130
} ;
132
131
}
@@ -236,6 +235,7 @@ impl HoleList {
236
235
}
237
236
238
237
#[ cfg( test) ]
238
+ #[ allow( dead_code) ]
239
239
pub ( crate ) fn debug ( & mut self ) {
240
240
if let Some ( cursor) = self . cursor ( ) {
241
241
let mut cursor = cursor;
@@ -261,11 +261,11 @@ impl HoleList {
261
261
262
262
/// Creates a `HoleList` that contains the given hole.
263
263
///
264
- /// ## Safety
264
+ /// # Safety
265
265
///
266
- /// This function is unsafe because it
267
- /// creates a hole at the given `hole_addr`. This can cause undefined behavior if this address
268
- /// is invalid or if memory from the `[hole_addr, hole_addr+size)` range is used somewhere else.
266
+ /// This function is unsafe because it creates a hole at the given `hole_addr`.
267
+ /// This can cause undefined behavior if this address is invalid or if memory from the
268
+ /// `[hole_addr, hole_addr+size)` range is used somewhere else.
269
269
///
270
270
/// The pointer to `hole_addr` is automatically aligned.
271
271
pub unsafe fn new ( hole_addr : * mut u8 , hole_size : usize ) -> HoleList {
@@ -314,6 +314,10 @@ impl HoleList {
314
314
///
315
315
/// This function uses the “first fit” strategy, so it uses the first hole that is big
316
316
/// enough. Thus the runtime is in O(n) but it should be reasonably fast for small allocations.
317
+ //
318
+ // NOTE: We could probably replace this with an `Option` instead of a `Result` in a later
319
+ // release to remove this clippy warning
320
+ #[ allow( clippy:: result_unit_err) ]
317
321
pub fn allocate_first_fit ( & mut self , layout : Layout ) -> Result < ( NonNull < u8 > , Layout ) , ( ) > {
318
322
let aligned_layout = Self :: align_layout ( layout) ;
319
323
let mut cursor = self . cursor ( ) . ok_or ( ( ) ) ?;
@@ -332,16 +336,18 @@ impl HoleList {
332
336
333
337
/// Frees the allocation given by `ptr` and `layout`.
334
338
///
335
- /// `ptr` must be a pointer returned by a call to the [`allocate_first_fit`] function with
336
- /// identical layout. Undefined behavior may occur for invalid arguments.
337
- /// The function performs exactly the same layout adjustments as [`allocate_first_fit`] and
338
- /// returns the aligned layout.
339
- ///
340
339
/// This function walks the list and inserts the given block at the correct place. If the freed
341
340
/// block is adjacent to another free block, the blocks are merged again.
342
341
/// This operation is in `O(n)` since the list needs to be sorted by address.
343
342
///
344
343
/// [`allocate_first_fit`]: HoleList::allocate_first_fit
344
+ ///
345
+ /// # Safety
346
+ ///
347
+ /// `ptr` must be a pointer returned by a call to the [`allocate_first_fit`] function with
348
+ /// identical layout. Undefined behavior may occur for invalid arguments.
349
+ /// The function performs exactly the same layout adjustments as [`allocate_first_fit`] and
350
+ /// returns the aligned layout.
345
351
pub unsafe fn deallocate ( & mut self , ptr : NonNull < u8 > , layout : Layout ) -> Layout {
346
352
let aligned_layout = Self :: align_layout ( layout) ;
347
353
deallocate ( self , ptr. as_ptr ( ) , aligned_layout. size ( ) ) ;
@@ -379,7 +385,11 @@ struct HoleInfo {
379
385
380
386
unsafe fn make_hole ( addr : * mut u8 , size : usize ) -> NonNull < Hole > {
381
387
let hole_addr = addr. cast :: < Hole > ( ) ;
382
- debug_assert_eq ! ( addr as usize % align_of:: <Hole >( ) , 0 ) ;
388
+ debug_assert_eq ! (
389
+ addr as usize % align_of:: <Hole >( ) ,
390
+ 0 ,
391
+ "Hole address not aligned!" ,
392
+ ) ;
383
393
hole_addr. write ( Hole { size, next : None } ) ;
384
394
NonNull :: new_unchecked ( hole_addr)
385
395
}
@@ -393,8 +403,11 @@ impl Cursor {
393
403
let node_size = unsafe { node. as_ref ( ) . size } ;
394
404
let hole_u8 = self . hole . as_ptr ( ) . cast :: < u8 > ( ) ;
395
405
396
- assert ! ( node_u8. wrapping_add( node_size) <= hole_u8) ;
397
- assert_eq ! ( self . previous( ) . size, 0 ) ;
406
+ assert ! (
407
+ node_u8. wrapping_add( node_size) <= hole_u8,
408
+ "Freed node aliases existing hole! Bad free?" ,
409
+ ) ;
410
+ debug_assert_eq ! ( self . previous( ) . size, 0 ) ;
398
411
399
412
let Cursor { mut prev, hole } = self ;
400
413
unsafe {
@@ -415,12 +428,18 @@ impl Cursor {
415
428
let hole_size = self . current ( ) . size ;
416
429
417
430
// Does hole overlap node?
418
- assert ! ( hole_u8. wrapping_add( hole_size) <= node_u8) ;
431
+ assert ! (
432
+ hole_u8. wrapping_add( hole_size) <= node_u8,
433
+ "Freed node aliases existing hole! Bad free?" ,
434
+ ) ;
419
435
420
436
// If we have a next, does the node overlap next?
421
437
if let Some ( next) = self . current ( ) . next . as_ref ( ) {
422
438
let node_u8 = node_u8 as * const u8 ;
423
- assert ! ( node_u8. wrapping_add( node_size) <= next. as_ptr( ) . cast:: <u8 >( ) )
439
+ assert ! (
440
+ node_u8. wrapping_add( node_size) <= next. as_ptr( ) . cast:: <u8 >( ) ,
441
+ "Freed node aliases existing hole! Bad free?" ,
442
+ ) ;
424
443
}
425
444
426
445
// All good! Let's insert that after.
@@ -447,6 +466,11 @@ impl Cursor {
447
466
} ;
448
467
449
468
// Can we directly merge these? e.g. are they touching?
469
+ //
470
+ // NOTE: Because we always use `HoleList::align_layout`, the size of
471
+ // the new hole is always "rounded up" to cover any partial gaps that
472
+ // would have occurred. For this reason, we DON'T need to "round up"
473
+ // to account for an unaligned hole spot.
450
474
let hole_u8 = hole. as_ptr ( ) . cast :: < u8 > ( ) ;
451
475
let hole_sz = unsafe { hole. as_ref ( ) . size } ;
452
476
let next_u8 = next. as_ptr ( ) . cast :: < u8 > ( ) ;
@@ -510,7 +534,9 @@ fn deallocate(list: &mut HoleList, addr: *mut u8, size: usize) {
510
534
Err ( mut cursor) => {
511
535
// Nope. It lives somewhere else. Advance the list until we find its home
512
536
while let Err ( ( ) ) = cursor. try_insert_after ( hole) {
513
- cursor = cursor. next ( ) . unwrap ( ) ;
537
+ cursor = cursor
538
+ . next ( )
539
+ . expect ( "Reached end of holes without finding deallocation hole!" ) ;
514
540
}
515
541
// Great! We found a home for it, our cursor is now JUST BEFORE the new
516
542
// node we inserted, so we need to try to merge up to twice: One to combine
0 commit comments