From 4d73c382ab83222c9ea10194e4270f1259c517b2 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 25 Aug 2010 12:35:52 +0000 Subject: 2010-08-25 Sebastian Huber PR 1672/cpukit * score/include/rtems/score/heap.h, score/src/heap.c, score/src/heapallocate.c, score/src/heapextend.c, score/src/heapfree.c, score/src/heapresizeblock.c, score/src/heapsizeofuserarea.c: Added heap protection in case RTEMS_DEBUG is defined. --- cpukit/score/src/heapfree.c | 93 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) (limited to 'cpukit/score/src/heapfree.c') diff --git a/cpukit/score/src/heapfree.c b/cpukit/score/src/heapfree.c index 48b54293ea..27e853d5bb 100644 --- a/cpukit/score/src/heapfree.c +++ b/cpukit/score/src/heapfree.c @@ -22,9 +22,89 @@ #endif #include -#include #include +#ifndef HEAP_PROTECTION + #define _Heap_Protection_determine_block_free( heap, block ) true +#else + static void _Heap_Protection_delay_block_free( + Heap_Control *heap, + Heap_Block *block + ) + { + uintptr_t *const pattern_begin = (uintptr_t *) + _Heap_Alloc_area_of_block( block ); + uintptr_t *const pattern_end = (uintptr_t *) + ((uintptr_t) block + _Heap_Block_size( block ) + HEAP_ALLOC_BONUS); + uintptr_t const delayed_free_block_count = + heap->Protection.delayed_free_block_count; + uintptr_t *current = NULL; + + block->Protection_begin.next_delayed_free_block = block; + block->Protection_begin.task = _Thread_Executing; + + if ( delayed_free_block_count > 0 ) { + Heap_Block *const last = heap->Protection.last_delayed_free_block; + + last->Protection_begin.next_delayed_free_block = block; + } else { + heap->Protection.first_delayed_free_block = block; + } + heap->Protection.last_delayed_free_block = block; + heap->Protection.delayed_free_block_count = delayed_free_block_count + 1; + + for ( current = pattern_begin; current != pattern_end; ++current ) { + *current = HEAP_FREE_PATTERN; + } + } + + static void _Heap_Protection_check_free_block( + Heap_Control *heap, + Heap_Block *block + ) + { + uintptr_t *const pattern_begin = (uintptr_t *) + _Heap_Alloc_area_of_block( block ); + uintptr_t *const pattern_end = (uintptr_t *) + ((uintptr_t) block + _Heap_Block_size( block ) + HEAP_ALLOC_BONUS); + uintptr_t *current = NULL; + + for ( current = pattern_begin; current != pattern_end; ++current ) { + if ( *current != HEAP_FREE_PATTERN ) { + _Heap_Protection_block_error( heap, block ); + break; + } + } + } + + static bool _Heap_Protection_determine_block_free( + Heap_Control *heap, + Heap_Block *block + ) + { + bool do_free = true; + + /* + * Sometimes after a free the allocated area is still in use. An example + * is the task stack of a thread that deletes itself. The thread dispatch + * disable level is a way to detect this use case. + */ + if ( _Thread_Dispatch_disable_level == 0 ) { + Heap_Block *const next = block->Protection_begin.next_delayed_free_block; + if ( next == NULL ) { + _Heap_Protection_delay_block_free( heap, block ); + do_free = false; + } else if ( next == HEAP_PROTECTION_OBOLUS ) { + _Heap_Protection_check_free_block( heap, block ); + } else { + _Heap_Protection_block_error( heap, block ); + } + } + + return do_free; + } +#endif + bool _Heap_Free( Heap_Control *heap, void *alloc_begin_ptr ) { Heap_Statistics *const stats = &heap->stats; @@ -36,6 +116,8 @@ bool _Heap_Free( Heap_Control *heap, void *alloc_begin_ptr ) uintptr_t next_block_size = 0; bool next_is_free = false; + _Heap_Protection_block_check( heap, block ); + if ( !_Heap_Is_block_in_heap( heap, block ) ) { return false; } @@ -43,16 +125,23 @@ bool _Heap_Free( Heap_Control *heap, void *alloc_begin_ptr ) block_size = _Heap_Block_size( block ); next_block = _Heap_Block_at( block, block_size ); + _Heap_Protection_block_check( heap, next_block ); + if ( !_Heap_Is_block_in_heap( heap, next_block ) ) { _HAssert( false ); return false; } if ( !_Heap_Is_prev_used( next_block ) ) { - _HAssert( false ); + _Heap_Protection_block_error( heap, block ); + return false; } + if ( !_Heap_Protection_determine_block_free( heap, block ) ) { + return true; + } + next_block_size = _Heap_Block_size( next_block ); next_is_free = next_block != heap->last_block && !_Heap_Is_prev_used( _Heap_Block_at( next_block, next_block_size )); -- cgit v1.2.3