summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-04-06 13:50:16 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2016-04-06 13:50:16 +0200
commitd7e68c96b46599c7f3277d04ec4d1107ac2ff594 (patch)
treebb3a1273e8eca5d87b81381d606b56a590be1f95
parentscore: Delete _Chain_Append() (diff)
downloadrtems-d7e68c96b46599c7f3277d04ec4d1107ac2ff594.tar.bz2
malloc: Fix early realloc() allocation
-rw-r--r--cpukit/libcsupport/src/malloc_deferred.c2
-rw-r--r--cpukit/libcsupport/src/malloc_p.h2
-rw-r--r--cpukit/libcsupport/src/realloc.c93
-rw-r--r--testsuites/libtests/malloctest/init.c17
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 <stdlib.h>
#include <errno.h>
+#include <stdlib.h>
#include <string.h>
-#include <rtems/score/sysstate.h>
-#include <rtems/score/objectimpl.h>
+#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(