diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2010-08-25 12:35:52 +0000 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2010-08-25 12:35:52 +0000 |
commit | 4d73c382ab83222c9ea10194e4270f1259c517b2 (patch) | |
tree | 573c748083714962a2ee08b7f6e37167bc58a7c7 /cpukit/score/src/heapfree.c | |
parent | 2010-08-25 Sebastian Huber <sebastian.huber@embedded-brains.de> (diff) | |
download | rtems-4d73c382ab83222c9ea10194e4270f1259c517b2.tar.bz2 |
2010-08-25 Sebastian Huber <sebastian.huber@embedded-brains.de>
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.
Diffstat (limited to 'cpukit/score/src/heapfree.c')
-rw-r--r-- | cpukit/score/src/heapfree.c | 93 |
1 files changed, 91 insertions, 2 deletions
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 <rtems/system.h> -#include <rtems/score/sysstate.h> #include <rtems/score/heap.h> +#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 )); |