mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-04 02:50:58 +02:00
multi_heap: Print the problem address when aborting due to heap corruption
New multi_heap code has proven effective at aborting when buffer overruns occur, but it's currently hard to debug the stack traces from these failures.
This commit is contained in:
committed by
Angus Gratton
parent
9a1ba5985b
commit
76d8190444
@@ -144,12 +144,14 @@ static inline size_t block_data_size(const heap_block_t *block)
|
||||
/* Check a block is valid for this heap. Used to verify parameters. */
|
||||
static void assert_valid_block(const heap_t *heap, const heap_block_t *block)
|
||||
{
|
||||
assert(block >= &heap->first_block && block <= heap->last_block); /* block should be in heap */
|
||||
MULTI_HEAP_ASSERT(block >= &heap->first_block && block <= heap->last_block,
|
||||
block); // block not in heap
|
||||
if (heap < (const heap_t *)heap->last_block) {
|
||||
const heap_block_t *next = get_next_block(block);
|
||||
assert(next >= &heap->first_block && next <= heap->last_block);
|
||||
MULTI_HEAP_ASSERT(next >= &heap->first_block && next <= heap->last_block, block); // Next block not in heap
|
||||
if (is_free(block)) {
|
||||
assert(block->next_free >= &heap->first_block && block->next_free <= heap->last_block);
|
||||
// Check block->next_free is valid
|
||||
MULTI_HEAP_ASSERT(block->next_free >= &heap->first_block && block->next_free <= heap->last_block, &block->next_free);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,10 +170,11 @@ static heap_block_t *get_prev_free_block(heap_t *heap, const heap_block_t *block
|
||||
assert(block != &heap->first_block); /* can't look for a block before first_block */
|
||||
|
||||
for (heap_block_t *b = &heap->first_block; b != NULL && b < block; b = b->next_free) {
|
||||
assert(is_free(b));
|
||||
MULTI_HEAP_ASSERT(is_free(b), b); // Block should be free
|
||||
if (b->next_free == NULL || b->next_free >= block) {
|
||||
if (is_free(block)) {
|
||||
assert(b->next_free == block); /* if block is on freelist, 'b' should be the item before it. */
|
||||
/* if block is on freelist, 'b' should be the item before it. */
|
||||
MULTI_HEAP_ASSERT(b->next_free == block, &b->next_free);
|
||||
}
|
||||
return b; /* b is the last free block before 'block' */
|
||||
}
|
||||
@@ -199,7 +202,7 @@ static heap_block_t *merge_adjacent(heap_t *heap, heap_block_t *a, heap_block_t
|
||||
return b;
|
||||
}
|
||||
|
||||
assert(get_next_block(a) == b);
|
||||
MULTI_HEAP_ASSERT(get_next_block(a) == b, a); // Blocks should be in order
|
||||
|
||||
bool free = is_free(a) && is_free(b); /* merging two free blocks creates a free block */
|
||||
if (!free && (is_free(a) || is_free(b))) {
|
||||
@@ -208,18 +211,20 @@ static heap_block_t *merge_adjacent(heap_t *heap, heap_block_t *a, heap_block_t
|
||||
*/
|
||||
heap_block_t *free_block = is_free(a) ? a : b;
|
||||
heap_block_t *prev_free = get_prev_free_block(heap, free_block);
|
||||
assert(free_block->next_free > prev_free);
|
||||
MULTI_HEAP_ASSERT(free_block->next_free > prev_free, &free_block->next_free); // Next free block should be after prev one
|
||||
prev_free->next_free = free_block->next_free;
|
||||
|
||||
heap->free_bytes -= block_data_size(free_block);
|
||||
}
|
||||
|
||||
a->header = b->header & NEXT_BLOCK_MASK;
|
||||
assert(a->header != 0);
|
||||
MULTI_HEAP_ASSERT(a->header != 0, a);
|
||||
if (free) {
|
||||
a->header |= BLOCK_FREE_FLAG;
|
||||
assert(b->next_free == NULL || b->next_free > a);
|
||||
assert(b->next_free == NULL || b->next_free > b);
|
||||
if (b->next_free != NULL) {
|
||||
MULTI_HEAP_ASSERT(b->next_free > a, &b->next_free);
|
||||
MULTI_HEAP_ASSERT(b->next_free > b, &b->next_free);
|
||||
}
|
||||
a->next_free = b->next_free;
|
||||
|
||||
/* b's header can be put into the pool of free bytes */
|
||||
@@ -245,8 +250,8 @@ static heap_block_t *merge_adjacent(heap_t *heap, heap_block_t *a, heap_block_t
|
||||
*/
|
||||
static void split_if_necessary(heap_t *heap, heap_block_t *block, size_t size, heap_block_t *prev_free_block)
|
||||
{
|
||||
assert(!is_free(block)); /* split_if_necessary doesn't expect a free block */
|
||||
assert(size <= block_data_size(block)); /* can't grow a block this way! */
|
||||
MULTI_HEAP_ASSERT(!is_free(block), block); // split block shouldn't be free
|
||||
MULTI_HEAP_ASSERT(size <= block_data_size(block), block); // size should be valid
|
||||
size = ALIGN_UP(size);
|
||||
|
||||
/* can't split the head or tail block */
|
||||
@@ -266,7 +271,9 @@ static void split_if_necessary(heap_t *heap, heap_block_t *block, size_t size, h
|
||||
if (prev_free_block == NULL) {
|
||||
prev_free_block = get_prev_free_block(heap, block);
|
||||
}
|
||||
assert(prev_free_block->next_free > new_block); /* prev_free_block should point to a free block after new_block */
|
||||
/* prev_free_block should point to a free block after new_block */
|
||||
MULTI_HEAP_ASSERT(prev_free_block->next_free > new_block,
|
||||
&prev_free_block->next_free); // free blocks should be in order
|
||||
new_block->next_free = prev_free_block->next_free;
|
||||
prev_free_block->next_free = new_block;
|
||||
heap->free_bytes += block_data_size(new_block);
|
||||
@@ -277,7 +284,7 @@ size_t multi_heap_get_allocated_size_impl(multi_heap_handle_t heap, void *p)
|
||||
heap_block_t *pb = get_block(p);
|
||||
|
||||
assert_valid_block(heap, pb);
|
||||
assert(!is_free(pb));
|
||||
MULTI_HEAP_ASSERT(!is_free(pb), pb); // block should be free
|
||||
return block_data_size(pb);
|
||||
}
|
||||
|
||||
@@ -339,7 +346,8 @@ void *multi_heap_malloc_impl(multi_heap_handle_t heap, size_t size)
|
||||
/* Find best free block to perform the allocation in */
|
||||
prev = &heap->first_block;
|
||||
for (heap_block_t *b = heap->first_block.next_free; b != NULL; b = b->next_free) {
|
||||
assert(is_free(b));
|
||||
MULTI_HEAP_ASSERT(b > prev, &prev->next_free); // free blocks should be ascending in address
|
||||
MULTI_HEAP_ASSERT(is_free(b), b); // block should be free
|
||||
size_t bs = block_data_size(b);
|
||||
if (bs >= size && bs < best_size) {
|
||||
best_block = b;
|
||||
@@ -384,15 +392,16 @@ void multi_heap_free_impl(multi_heap_handle_t heap, void *p)
|
||||
MULTI_HEAP_LOCK(heap->lock);
|
||||
|
||||
assert_valid_block(heap, pb);
|
||||
assert(!is_free(pb));
|
||||
assert(!is_last_block(pb));
|
||||
assert(pb != &heap->first_block);
|
||||
MULTI_HEAP_ASSERT(!is_free(pb), pb); // block should not be free
|
||||
MULTI_HEAP_ASSERT(!is_last_block(pb), pb); // block should not be last block
|
||||
MULTI_HEAP_ASSERT(pb != &heap->first_block, pb); // block should not be first block
|
||||
|
||||
heap_block_t *next = get_next_block(pb);
|
||||
|
||||
/* Update freelist pointers */
|
||||
heap_block_t *prev_free = get_prev_free_block(heap, pb);
|
||||
assert(prev_free->next_free == NULL || prev_free->next_free > pb);
|
||||
// freelist validity check
|
||||
MULTI_HEAP_ASSERT(prev_free->next_free == NULL || prev_free->next_free > pb, &prev_free->next_free);
|
||||
pb->next_free = prev_free->next_free;
|
||||
prev_free->next_free = pb;
|
||||
|
||||
@@ -428,7 +437,8 @@ void *multi_heap_realloc_impl(multi_heap_handle_t heap, void *p, size_t size)
|
||||
}
|
||||
|
||||
assert_valid_block(heap, pb);
|
||||
assert(!is_free(pb) && "realloc arg should be allocated");
|
||||
// non-null realloc arg should be allocated
|
||||
MULTI_HEAP_ASSERT(!is_free(pb), pb);
|
||||
|
||||
if (size == 0) {
|
||||
/* note: calling multi_free_impl() here as we've already been
|
||||
@@ -646,7 +656,8 @@ void multi_heap_get_info_impl(multi_heap_handle_t heap, multi_heap_info_t *info)
|
||||
}
|
||||
|
||||
info->minimum_free_bytes = heap->minimum_free_bytes;
|
||||
assert(info->total_free_bytes == heap->free_bytes);
|
||||
// heap has wrong total size (address printed here is not indicative of the real error)
|
||||
MULTI_HEAP_ASSERT(info->total_free_bytes == heap->free_bytes, heap);
|
||||
|
||||
MULTI_HEAP_UNLOCK(heap->lock);
|
||||
|
||||
|
Reference in New Issue
Block a user