summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/heapfree.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2010-08-25 12:35:52 +0000
committerSebastian Huber <sebastian.huber@embedded-brains.de>2010-08-25 12:35:52 +0000
commit4d73c382ab83222c9ea10194e4270f1259c517b2 (patch)
tree573c748083714962a2ee08b7f6e37167bc58a7c7 /cpukit/score/src/heapfree.c
parent2010-08-25 Sebastian Huber <sebastian.huber@embedded-brains.de> (diff)
downloadrtems-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.c93
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 ));