From f0db26604f5ea589616481f35db6f2c46dfa2bb2 Mon Sep 17 00:00:00 2001
From: Angus Gratton <gus@projectgus.com>
Date: Tue, 16 Feb 2016 22:00:29 +1100
Subject: [PATCH] brk/malloc: Allow malloc to fail when out of RAM

Fixes #76.
---
 FreeRTOS/Source/portable/esp8266/port.c | 13 +++++++------
 core/newlib_syscalls.c                  | 21 ++++++++++++++-------
 ld/common.ld                            |  2 +-
 3 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/FreeRTOS/Source/portable/esp8266/port.c b/FreeRTOS/Source/portable/esp8266/port.c
index a9dac2d..54bca65 100644
--- a/FreeRTOS/Source/portable/esp8266/port.c
+++ b/FreeRTOS/Source/portable/esp8266/port.c
@@ -82,13 +82,14 @@
 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. This is the "high water mark" of
+   how far the supervisor stack grew down before task started. Is zero
+   before the scheduler starts.
 
-   After tasks start, task stacks are all allocated from the heap and
-   FreeRTOS checks for stack overflow.
+ After the scheduler starts, task stacks are all allocated from the
+ heap and FreeRTOS checks for stack overflow.
 */
-uint32_t xPortSupervisorStackPointer;
+void *xPortSupervisorStackPointer;
 
 /*
  * Stack initialization
@@ -219,7 +220,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 */
         SP(sp);
     return sp - brk_val + mi.fordblks;
diff --git a/core/newlib_syscalls.c b/core/newlib_syscalls.c
index 0d4b95e..023872c 100644
--- a/core/newlib_syscalls.c
+++ b/core/newlib_syscalls.c
@@ -9,9 +9,12 @@
 #include <sys/errno.h>
 #include <espressif/sdk_private.h>
 #include <common_macros.h>
+#include <xtensa_ops.h>
 #include <esp/uart.h>
 #include <stdlib.h>
 
+extern void *xPortSupervisorStackPointer;
+
 IRAM caddr_t _sbrk_r (struct _reent *r, int incr)
 {
     extern char   _heap_start; /* linker script defined */
@@ -21,13 +24,17 @@ 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);
-       abort();
-       }
-    */
+
+    intptr_t sp = (intptr_t)xPortSupervisorStackPointer;
+    if(sp == 0) /* scheduler not started */
+        SP(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)
   {