From 8fffd14e50fa813606a4561c1283728e1a20fbeb Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 16 Feb 2016 22:00:29 +1100 Subject: [PATCH] tests/malloc: Allow malloc to fail when out of RAM, add heap test cases. Fixes #76. --- FreeRTOS/Source/portable/esp8266/port.c | 15 +++++++++------ core/newlib_syscalls.c | 19 ++++++++++++------- ld/common.ld | 2 +- tests/cases/02_heap.c | 19 +++++++++++++++++++ 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/FreeRTOS/Source/portable/esp8266/port.c b/FreeRTOS/Source/portable/esp8266/port.c index 21a0d55..a86e7d9 100644 --- a/FreeRTOS/Source/portable/esp8266/port.c +++ b/FreeRTOS/Source/portable/esp8266/port.c @@ -81,13 +81,16 @@ unsigned cpu_sr; char level1_int_disabled; -/* Supervisor stack pointer entry. This is the "high water mark" of how far the - supervisor stack grew down before task started. +/* Supervisor stack pointer entry. On reset, sdk_user_start sets a + * tentative 512 byte supervisor stack size. - After tasks start, task stacks are all allocated from the heap and - FreeRTOS checks for stack overflow. + When the scheduler starts, this changes to the "high water mark" of + how far the supervisor stack grew down before task started. + + After tasks start, task stacks are all allocated from the heap and + FreeRTOS checks for stack overflow. */ -static uint32_t xPortSupervisorStackPointer; +void *xPortSupervisorStackPointer; /* * Stack initialization @@ -218,7 +221,7 @@ size_t xPortGetFreeHeapSize( void ) struct mallinfo mi = mallinfo(); uint32_t brk_val = (uint32_t) sbrk(0); - uint32_t sp = xPortSupervisorStackPointer; + intptr_t sp = (intptr_t)xPortSupervisorStackPointer; if(sp == 0) /* scheduler not started */ __asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp)); return sp - brk_val + mi.fordblks; diff --git a/core/newlib_syscalls.c b/core/newlib_syscalls.c index b414481..1758065 100644 --- a/core/newlib_syscalls.c +++ b/core/newlib_syscalls.c @@ -12,6 +12,8 @@ #include #include +extern void *xPortSupervisorStackPointer; + IRAM caddr_t _sbrk_r (struct _reent *r, int incr) { extern char _heap_start; /* linker script defined */ @@ -21,13 +23,16 @@ IRAM caddr_t _sbrk_r (struct _reent *r, int incr) if (heap_end == NULL) heap_end = &_heap_start; prev_heap_end = heap_end; - /* TODO: Check stack collision - if (heap_end + incr > stack_ptr) - { - _write (1, "_sbrk: Heap collided with stack\n", 32); - while(1) {} - } - */ + + intptr_t sp = (intptr_t)xPortSupervisorStackPointer; + if(sp == 0) /* scheduler not started */ + __asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp)); + + if ((intptr_t)heap_end + incr >= sp) + { + r->_errno = ENOMEM; + return (caddr_t)-1; + } heap_end += incr; return (caddr_t) prev_heap_end; diff --git a/ld/common.ld b/ld/common.ld index cc8a8ce..b728ea0 100644 --- a/ld/common.ld +++ b/ld/common.ld @@ -232,7 +232,7 @@ SECTIONS _heap_start = ABSOLUTE(.); /* _stack_sentry = ALIGN(0x8); */ } >dram0_0_seg :dram0_0_bss_phdr -/* __stack = 0x3ffc8000; */ +/* __stack = 0x3ffc8000; <-- this value seems a bit odd, stack on sdk_user_start is ~0x3ffffce9 */ .lit4 : ALIGN(4) { diff --git a/tests/cases/02_heap.c b/tests/cases/02_heap.c index a779e3a..8380574 100644 --- a/tests/cases/02_heap.c +++ b/tests/cases/02_heap.c @@ -4,6 +4,7 @@ #include DEFINE_SOLO_TESTCASE(02_heap_simple) +DEFINE_SOLO_TESTCASE(02_heap_full) /* Simple heap accounting tests */ static void a_02_heap_simple() @@ -35,3 +36,21 @@ static void a_02_heap_simple() TEST_ASSERT_UINT32_WITHIN_MESSAGE(100, freeheap, after, "Free heap size after freeing buffer should be close to initial"); TEST_PASS; } + +/* Ensure malloc behaves when out of memory */ +static void a_02_heap_full() +{ + void *x = malloc(65536); + TEST_ASSERT_NULL_MESSAGE(x, "Allocating 64kB should fail and return null"); + + void *y = malloc(32768); + TEST_ASSERT_NOT_NULL_MESSAGE(y, "Allocating 32kB should succeed"); + + void *z = malloc(32768); + TEST_ASSERT_NULL_MESSAGE(z, "Allocating second 32kB should fail"); + + free(y); + z = malloc(32768); + TEST_ASSERT_NOT_NULL_MESSAGE(z, "Allocating 32kB should succeed after first block freed"); + TEST_PASS; +}