From d7e68c96b46599c7f3277d04ec4d1107ac2ff594 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 6 Apr 2016 13:50:16 +0200 Subject: malloc: Fix early realloc() allocation --- cpukit/libcsupport/src/malloc_deferred.c | 2 +- cpukit/libcsupport/src/malloc_p.h | 2 + cpukit/libcsupport/src/realloc.c | 93 ++++++++++++++++---------------- testsuites/libtests/malloctest/init.c | 17 ++++++ 4 files changed, 68 insertions(+), 46 deletions(-) diff --git a/cpukit/libcsupport/src/malloc_deferred.c b/cpukit/libcsupport/src/malloc_deferred.c index 2a4f5c892b..977ec7b3f6 100644 --- a/cpukit/libcsupport/src/malloc_deferred.c +++ b/cpukit/libcsupport/src/malloc_deferred.c @@ -63,7 +63,7 @@ static void *_Malloc_Get_deferred_free( void ) return p; } -static void _Malloc_Process_deferred_frees( void ) +void _Malloc_Process_deferred_frees( void ) { rtems_chain_node *to_be_freed; diff --git a/cpukit/libcsupport/src/malloc_p.h b/cpukit/libcsupport/src/malloc_p.h index 127f22bac4..f3715a9966 100644 --- a/cpukit/libcsupport/src/malloc_p.h +++ b/cpukit/libcsupport/src/malloc_p.h @@ -27,6 +27,8 @@ Malloc_System_state _Malloc_System_state( void ); void _Malloc_Deferred_free( void * ); +void _Malloc_Process_deferred_frees( void ); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/cpukit/libcsupport/src/realloc.c b/cpukit/libcsupport/src/realloc.c index 6efdfdfdb8..7912780c09 100644 --- a/cpukit/libcsupport/src/realloc.c +++ b/cpukit/libcsupport/src/realloc.c @@ -19,70 +19,73 @@ #endif #ifdef RTEMS_NEWLIB -#include "malloc_p.h" -#include #include +#include #include -#include -#include +#include "malloc_p.h" -void *realloc( - void *ptr, - size_t size -) +static void *new_alloc( void *old_ptr, size_t new_size, size_t old_size ) { - uintptr_t old_size; - char *new_area; + void *new_ptr; /* - * Do not attempt to allocate memory if in a critical section or ISR. + * There used to be a free on this error case but it is wrong to + * free the memory per OpenGroup Single UNIX Specification V2 + * and the C Standard. */ - if (_System_state_Is_up(_System_state_Get())) { - if (!_Thread_Dispatch_is_enabled()) - return (void *) 0; + new_ptr = malloc( new_size ); + if ( new_ptr == NULL ) { + return NULL; } - /* - * Continue with realloc(). - */ - if ( !ptr ) - return malloc( size ); + memcpy( new_ptr, old_ptr, ( new_size < old_size ) ? new_size : old_size ); + free( old_ptr ); + + return new_ptr; +} + +void *realloc( void *ptr, size_t size ) +{ + Heap_Control *heap; + Heap_Resize_status status; + uintptr_t old_size; + uintptr_t avail_size; - if ( !size ) { + if ( size == 0 ) { free( ptr ); - return (void *) 0; + return NULL; } - if ( !_Protected_heap_Get_block_size(RTEMS_Malloc_Heap, ptr, &old_size) ) { - errno = EINVAL; - return (void *) 0; + if ( ptr == NULL ) { + return malloc( size ); } - /* - * Now resize it. - */ - if ( _Protected_heap_Resize_block( RTEMS_Malloc_Heap, ptr, size ) ) { - return ptr; + heap = RTEMS_Malloc_Heap; + + switch ( _Malloc_System_state() ) { + case MALLOC_SYSTEM_STATE_NORMAL: + _RTEMS_Lock_allocator(); + _Malloc_Process_deferred_frees(); + status = _Heap_Resize_block( heap, ptr, size, &old_size, &avail_size ); + _RTEMS_Unlock_allocator(); + break; + case MALLOC_SYSTEM_STATE_NO_PROTECTION: + status = _Heap_Resize_block( heap, ptr, size, &old_size, &avail_size ); + break; + default: + return NULL; } - /* - * There used to be a free on this error case but it is wrong to - * free the memory per OpenGroup Single UNIX Specification V2 - * and the C Standard. - */ - - new_area = malloc( size ); - - if ( !new_area ) { - return (void *) 0; + switch ( status ) { + case HEAP_RESIZE_SUCCESSFUL: + return ptr; + case HEAP_RESIZE_UNSATISFIED: + return new_alloc( ptr, size, old_size ); + default: + errno = EINVAL; + return NULL; } - - memcpy( new_area, ptr, (size < old_size) ? size : old_size ); - free( ptr ); - - return new_area; - } #endif diff --git a/testsuites/libtests/malloctest/init.c b/testsuites/libtests/malloctest/init.c index acf25d7cc5..6123977ff7 100644 --- a/testsuites/libtests/malloctest/init.c +++ b/testsuites/libtests/malloctest/init.c @@ -1375,6 +1375,9 @@ static void test_early_malloc( void ) { void *p; char *q; + void *r; + void *s; + void *t; p = malloc( 1 ); rtems_test_assert( p != NULL ); @@ -1387,6 +1390,20 @@ static void test_early_malloc( void ) rtems_test_assert( q[0] == 0 ); free( q ); + + r = realloc( q, 128 ); + rtems_test_assert( r == q ); + + s = malloc( 1 ); + rtems_test_assert( s != NULL ); + + free( s ); + + t = realloc( r, 256 ); + rtems_test_assert( t != NULL ); + rtems_test_assert( t != r ); + + free( t ); } RTEMS_SYSINIT_ITEM( -- cgit v1.2.3