From d3b1f0b627ccc6705d9fe958549badb87a74ded1 Mon Sep 17 00:00:00 2001
From: Paul Sokolovsky <pfalcon@users.sourceforge.net>
Date: Fri, 29 Jan 2016 01:05:53 +0200
Subject: [PATCH] py/runtime: mp_stack_ctrl_init() should be called immediately
 on startup.

Calling it from mp_init() is too late for some ports (like Unix), and leads
to incomplete stack frame being captured, with following GC issues. So, now
each port should call mp_stack_ctrl_init() on its own, ASAP after startup,
and taking special precautions so it really was called before stack variables
get allocated (because if such variable with a pointer is missed, it may lead
to over-collecting (typical symptom is segfaulting)).
---
 py/runtime.c           |  1 -
 qemu-arm/main.c        |  1 +
 qemu-arm/test_main.c   |  1 +
 stmhal/main.c          |  1 +
 teensy/main.c          |  1 +
 unix/main.c            | 12 ++++++++++++
 unix/mpconfigport.h    |  4 ++++
 windows/mpconfigport.h |  5 +++++
 8 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/py/runtime.c b/py/runtime.c
index b0f407a15..e4a4d5b3f 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -61,7 +61,6 @@ const mp_obj_module_t mp_module___main__ = {
 
 void mp_init(void) {
     qstr_init();
-    mp_stack_ctrl_init();
 
     // no pending exceptions to start with
     MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
diff --git a/qemu-arm/main.c b/qemu-arm/main.c
index f29547523..b6ff73980 100644
--- a/qemu-arm/main.c
+++ b/qemu-arm/main.c
@@ -32,6 +32,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
 }
 
 int main(int argc, char **argv) {
+    mp_stack_ctrl_init();
     mp_stack_set_limit(10240);
     void *heap = malloc(16 * 1024);
     gc_init(heap, (char*)heap + 16 * 1024);
diff --git a/qemu-arm/test_main.c b/qemu-arm/test_main.c
index a98e275ce..44f9cc666 100644
--- a/qemu-arm/test_main.c
+++ b/qemu-arm/test_main.c
@@ -49,6 +49,7 @@ end:
 
 int main() {
     const char a[] = {"sim"};
+    mp_stack_ctrl_init();
     mp_stack_set_limit(10240);
     void *heap = malloc(256 * 1024);
     gc_init(heap, (char*)heap + 256 * 1024);
diff --git a/stmhal/main.c b/stmhal/main.c
index cce114605..0e5fc44af 100644
--- a/stmhal/main.c
+++ b/stmhal/main.c
@@ -335,6 +335,7 @@ int main(void) {
 
     // Stack limit should be less than real stack size, so we have a chance
     // to recover from limit hit.  (Limit is measured in bytes.)
+    mp_stack_ctrl_init();
     mp_stack_set_limit((char*)&_ram_end - (char*)&_heap_end - 1024);
 
     /* STM32F4xx HAL library initialization:
diff --git a/teensy/main.c b/teensy/main.c
index b630e8886..41e445cb5 100644
--- a/teensy/main.c
+++ b/teensy/main.c
@@ -253,6 +253,7 @@ int main(void) {
     #define SCB_CCR_STKALIGN (1 << 9)
     SCB_CCR |= SCB_CCR_STKALIGN;
 
+    mp_stack_ctrl_init();
     mp_stack_set_limit(10240);
 
     pinMode(LED_BUILTIN, OUTPUT);
diff --git a/unix/main.c b/unix/main.c
index 03902a3e9..4ba68dcb9 100644
--- a/unix/main.c
+++ b/unix/main.c
@@ -376,7 +376,19 @@ STATIC void set_sys_argv(char *argv[], int argc, int start_arg) {
 #define PATHLIST_SEP_CHAR ':'
 #endif
 
+MP_NOINLINE int main_(int argc, char **argv);
+
 int main(int argc, char **argv) {
+    // We should capture stack top ASAP after start, and it should be
+    // captured guaranteedly before any other stack variables are allocated.
+    // For this, actual main (renamed main_) should not be inlined into
+    // this function. main_() itself may have other functions inlined (with
+    // their own stack variables), that's why we need this main/main_ split.
+    mp_stack_ctrl_init();
+    return main_(argc, argv);
+}
+
+MP_NOINLINE int main_(int argc, char **argv) {
     mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4));
 
     pre_process_options(argc, argv);
diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h
index 2f992fdf0..f7fdeec07 100644
--- a/unix/mpconfigport.h
+++ b/unix/mpconfigport.h
@@ -214,6 +214,10 @@ void mp_unix_mark_exec(void);
 #define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) mp_unix_alloc_exec(min_size, ptr, size)
 #define MP_PLAT_FREE_EXEC(ptr, size) mp_unix_free_exec(ptr, size)
 
+#ifndef MP_NOINLINE
+#define MP_NOINLINE __attribute__((noinline))
+#endif
+
 #if MICROPY_PY_OS_DUPTERM
 #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
 #else
diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h
index 80166f149..ad79ef381 100644
--- a/windows/mpconfigport.h
+++ b/windows/mpconfigport.h
@@ -178,6 +178,10 @@ extern const struct _mp_obj_module_t mp_module_time;
 #include "init.h"
 #include "sleep.h"
 
+#ifdef __GNUC__
+#define MP_NOINLINE __attribute__((noinline))
+#endif
+
 // MSVC specifics
 #ifdef _MSC_VER
 
@@ -191,6 +195,7 @@ extern const struct _mp_obj_module_t mp_module_time;
 // CL specific overrides from mpconfig
 
 #define NORETURN                    __declspec(noreturn)
+#define MP_NOINLINE                 __declspec(noinline)
 #define MP_LIKELY(x)                (x)
 #define MP_UNLIKELY(x)              (x)
 #define MICROPY_PORT_CONSTANTS      { "dummy", 0 } //can't have zero-sized array
-- 
GitLab