mirror of https://github.com/ipxe/ipxe.git
[malloc] Check integrity of free list
Check the integrity of the free memory block list before and after any modifications to the list. We check that certain invariants are preserved: - the list is a well-formed doubly linked list - all blocks are at least MIN_MEMBLOCK_SIZE - no block extends beyond the end of our address space - blocks remain sorted in ascending order of address - no blocks are adjacent (i.e. any adjacent blocks have been merged) Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/33/head
parent
9154f2aef3
commit
7871666740
|
@ -186,6 +186,42 @@ static inline void valgrind_make_blocks_noaccess ( void ) {
|
||||||
VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks, sizeof ( free_blocks ) );
|
VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks, sizeof ( free_blocks ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check integrity of the blocks in the free list
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static inline void check_blocks ( void ) {
|
||||||
|
struct memory_block *block;
|
||||||
|
struct memory_block *prev = NULL;
|
||||||
|
|
||||||
|
if ( ! ASSERTING )
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_for_each_entry ( block, &free_blocks, list ) {
|
||||||
|
|
||||||
|
/* Check that list structure is intact */
|
||||||
|
list_check ( &block->list );
|
||||||
|
|
||||||
|
/* Check that block size is not too small */
|
||||||
|
assert ( block->size >= sizeof ( *block ) );
|
||||||
|
assert ( block->size >= MIN_MEMBLOCK_SIZE );
|
||||||
|
|
||||||
|
/* Check that block does not wrap beyond end of address space */
|
||||||
|
assert ( ( ( void * ) block + block->size ) >
|
||||||
|
( ( void * ) block ) );
|
||||||
|
|
||||||
|
/* Check that blocks remain in ascending order, and
|
||||||
|
* that adjacent blocks have been merged.
|
||||||
|
*/
|
||||||
|
if ( prev ) {
|
||||||
|
assert ( ( ( void * ) block ) > ( ( void * ) prev ) );
|
||||||
|
assert ( ( ( void * ) block ) >
|
||||||
|
( ( ( void * ) prev ) + prev->size ) );
|
||||||
|
}
|
||||||
|
prev = block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discard some cached data
|
* Discard some cached data
|
||||||
*
|
*
|
||||||
|
@ -242,6 +278,7 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
|
||||||
assert ( ( align == 0 ) || ( ( align & ( align - 1 ) ) == 0 ) );
|
assert ( ( align == 0 ) || ( ( align & ( align - 1 ) ) == 0 ) );
|
||||||
|
|
||||||
valgrind_make_blocks_defined();
|
valgrind_make_blocks_defined();
|
||||||
|
check_blocks();
|
||||||
|
|
||||||
/* Round up size to multiple of MIN_MEMBLOCK_SIZE and
|
/* Round up size to multiple of MIN_MEMBLOCK_SIZE and
|
||||||
* calculate alignment mask.
|
* calculate alignment mask.
|
||||||
|
@ -314,6 +351,7 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
check_blocks();
|
||||||
valgrind_make_blocks_noaccess();
|
valgrind_make_blocks_noaccess();
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
@ -338,6 +376,7 @@ void free_memblock ( void *ptr, size_t size ) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
valgrind_make_blocks_defined();
|
valgrind_make_blocks_defined();
|
||||||
|
check_blocks();
|
||||||
|
|
||||||
/* Round up size to match actual size that alloc_memblock()
|
/* Round up size to match actual size that alloc_memblock()
|
||||||
* would have used.
|
* would have used.
|
||||||
|
@ -346,11 +385,29 @@ void free_memblock ( void *ptr, size_t size ) {
|
||||||
size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
|
size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
|
||||||
freeing = ptr;
|
freeing = ptr;
|
||||||
VALGRIND_MAKE_MEM_DEFINED ( freeing, sizeof ( *freeing ) );
|
VALGRIND_MAKE_MEM_DEFINED ( freeing, sizeof ( *freeing ) );
|
||||||
freeing->size = size;
|
|
||||||
DBGC2 ( &heap, "Freeing [%p,%p)\n",
|
DBGC2 ( &heap, "Freeing [%p,%p)\n",
|
||||||
freeing, ( ( ( void * ) freeing ) + size ) );
|
freeing, ( ( ( void * ) freeing ) + size ) );
|
||||||
|
|
||||||
|
/* Check that this block does not overlap the free list */
|
||||||
|
if ( ASSERTING ) {
|
||||||
|
list_for_each_entry ( block, &free_blocks, list ) {
|
||||||
|
if ( ( ( ( void * ) block ) <
|
||||||
|
( ( void * ) freeing + size ) ) &&
|
||||||
|
( ( void * ) freeing <
|
||||||
|
( ( void * ) block + block->size ) ) ) {
|
||||||
|
assert ( 0 );
|
||||||
|
DBGC ( &heap, "Double free of [%p,%p) "
|
||||||
|
"overlapping [%p,%p) detected from %p\n",
|
||||||
|
freeing,
|
||||||
|
( ( ( void * ) freeing ) + size ), block,
|
||||||
|
( ( void * ) block + block->size ),
|
||||||
|
__builtin_return_address ( 0 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Insert/merge into free list */
|
/* Insert/merge into free list */
|
||||||
|
freeing->size = size;
|
||||||
list_for_each_entry_safe ( block, tmp, &free_blocks, list ) {
|
list_for_each_entry_safe ( block, tmp, &free_blocks, list ) {
|
||||||
/* Calculate gaps before and after the "freeing" block */
|
/* Calculate gaps before and after the "freeing" block */
|
||||||
gap_before = ( ( ( void * ) freeing ) -
|
gap_before = ( ( ( void * ) freeing ) -
|
||||||
|
@ -392,6 +449,7 @@ void free_memblock ( void *ptr, size_t size ) {
|
||||||
/* Update free memory counter */
|
/* Update free memory counter */
|
||||||
freemem += size;
|
freemem += size;
|
||||||
|
|
||||||
|
check_blocks();
|
||||||
valgrind_make_blocks_noaccess();
|
valgrind_make_blocks_noaccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue