From 92c28e5fc757c9475698e9bccc4d6fc7660b479e Mon Sep 17 00:00:00 2001 From: Fabian Vogt Date: Sat, 15 May 2021 18:58:11 +0200 Subject: [PATCH 1/2] Only perform cleanup when exiting cleanly In some circumstances, it's important to skip cleanup on exit, like in the case of crash handlers and especially for resident programs. --- ndless-sdk/include/nucleus.h | 3 +++ ndless-sdk/libsyscalls/stdlib.cpp | 29 ++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/ndless-sdk/include/nucleus.h b/ndless-sdk/include/nucleus.h index 3ef849a9..9d667d91 100644 --- a/ndless-sdk/include/nucleus.h +++ b/ndless-sdk/include/nucleus.h @@ -124,6 +124,9 @@ unsigned int nl_hwsubtype(); BOOL nl_loaded_by_3rd_party_loader(); BOOL nl_isstartup(); BOOL _nl_hassyscall(int nr); +// Mark the program as resident, i.e. don't unload the executable on exit. +// Instead of calling exit or return from main, _exit has to be used. +// Otherwise cleanup breaks some library functions! void nl_set_resident(); unsigned int nl_osvalue(const unsigned int *values, unsigned size); int nl_exec(const char* prg, int argc, char** argv); diff --git a/ndless-sdk/libsyscalls/stdlib.cpp b/ndless-sdk/libsyscalls/stdlib.cpp index e5f5b031..a796208c 100644 --- a/ndless-sdk/libsyscalls/stdlib.cpp +++ b/ndless-sdk/libsyscalls/stdlib.cpp @@ -46,10 +46,13 @@ constexpr int MAX_OPEN_FILES = 20; static NUC_FILE* openfiles[MAX_OPEN_FILES]; static void* saved_screen_buffer; //In case the program changes the buffer +static bool is_clean_exit = false; // Whether returned from main or exit called + #ifdef USE_NSPIREIO #include static nio_console csl; + static bool nio_ready = false; #endif // Called at startup (even before c++ constructors are run) @@ -65,7 +68,10 @@ void initialise_monitor_handles() nio_init(&csl,NIO_MAX_COLS,NIO_MAX_ROWS,0,0,NIO_COLOR_BLACK,NIO_COLOR_WHITE,TRUE); nio_set_default(&csl); nio_fflush(&csl); + nio_ready = true; #endif + + atexit([] { is_clean_exit = true; }); } static int newslot() @@ -183,13 +189,14 @@ void *calloc(size_t nmemb, size_t size) int _puts(const char *s) { #ifdef USE_NSPIREIO - return nio_puts(s); -#else - return syscall(s); + if(nio_ready) + return nio_puts(s); #endif + + return syscall(s); } -void __crt0_exit(int ret); // Declared in crt0.S +void __attribute__((noreturn)) __crt0_exit(int ret); // Declared in crt0.S void _exit(int ret) { @@ -199,9 +206,15 @@ void _exit(int ret) // it the right place for deinititalizing nspireio, as after this // nothing has access to csl anymore and newlib itself won't flush // its buffers either. - nio_free(&csl); + if(nio_ready) + nio_free(&csl); + nio_ready = false; #endif + // When calling _exit, don't perform any cleanup + if(!is_clean_exit) + __crt0_exit(ret); + // Free memory allocated by libstdc++ if(__gnu_cxx::__freeres) __gnu_cxx::__freeres(); @@ -214,8 +227,6 @@ void _exit(int ret) _reclaim_reent(global_reent); __crt0_exit(ret); - - __builtin_unreachable(); } std::type_info* __cxa_current_exception_type() __attribute__((weak)); @@ -314,7 +325,7 @@ int _fstat(int file, struct stat *st) int _read(int file, char *ptr, int len) { #ifdef USE_NSPIREIO - if(file == 0) + if(file == 0 && nio_ready) { if(!nio_fgets(ptr, len - 1, &csl)) *ptr = 0; @@ -344,7 +355,7 @@ int _read(int file, char *ptr, int len) int _write(int file, char *ptr, int len) { #ifdef USE_NSPIREIO - if(file == 1 || file == 2) + if((file == 1 || file == 2) && nio_ready) { int len2 = len; while(len2--) From c082cb13e8c0bc62d6371551a99023582390bfd6 Mon Sep 17 00:00:00 2001 From: Fabian Vogt Date: Sat, 15 May 2021 19:04:26 +0200 Subject: [PATCH 2/2] Call _exit in luaextdemo Otherwise libc is deinitialized and calling printf crashes. --- ndless-sdk/samples/luaext/luaextdemo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ndless-sdk/samples/luaext/luaextdemo.c b/ndless-sdk/samples/luaext/luaextdemo.c index e23d3537..e9db9d4b 100644 --- a/ndless-sdk/samples/luaext/luaextdemo.c +++ b/ndless-sdk/samples/luaext/luaextdemo.c @@ -17,5 +17,7 @@ int main(void) { lua_State *L = nl_lua_getstate(); if (!L) return 0; // not being called as Lua module luaL_register(L, "luaextdemo", lualib); - return 0; + + // Skip cleanup on exit, this is a resident program + _exit(0); }