diff --git a/source/lib/debug.cpp b/source/lib/debug.cpp index e78dbaea40..881de49067 100644 --- a/source/lib/debug.cpp +++ b/source/lib/debug.cpp @@ -26,11 +26,12 @@ #include #include -#include "lib/posix/posix_pthread.h" #include "lib.h" #include "app_hooks.h" #include "path_util.h" #include "debug_stl.h" +#include "allocators.h" +#include "lib/posix/posix_pthread.h" #include "lib/sysdep/cpu.h" // CAS #include "lib/sysdep/sysdep.h" #include "lib/res/file/file.h" // FILE_ACCESS @@ -504,45 +505,12 @@ static bool should_suppress_error(u8* suppress) return false; } -static wchar_t* alloc_mem(void* alloca_buf, size_t alloca_buf_size, - void*& heap_mem, size_t& max_chars) -{ - void* chosen_buf; - size_t chosen_size; - - // rationale: - // - this needs to be quite large, so preallocating is undesirable. - // - prefer malloc to alloca because it allows returning larger - // buffers (stack space may be quite limited). - // - do not rely on malloc because we might be called upon to report - // heap corruption errors. therefore, the caller should allocate some - // scratch memory via alloca, which is used as an (optional) backup. - // - note: we can't alloca here because it'd be lost after - // function return, but must be passed on to debug_display_error. - - // try allocating from heap. - chosen_size = 500*KiB; // 'enough' - chosen_buf = heap_mem = malloc(chosen_size); - // .. failed; use alloca_buf. - if(!chosen_buf) - { - // caller didn't set it up => we have no memory to return; abort. - if(!alloca_buf) - return 0; - - chosen_buf = alloca_buf; - chosen_size = alloca_buf_size; - } - - max_chars = chosen_size / sizeof(wchar_t); - return (wchar_t*)chosen_buf; -} +static const size_t message_size_bytes = 256*KiB; // enough void debug_error_message_free(ErrorMessageMem* emm) { - // note: no-op if wasn't allocated from heap. - free(emm->heap_mem); + page_aligned_free(emm->pa_mem, message_size_bytes); } // split out of debug_display_error because it's used by the self-test. @@ -552,10 +520,12 @@ const wchar_t* debug_error_message_build( uint skip, void* context, ErrorMessageMem* emm) { - size_t max_chars; - wchar_t* buf = alloc_mem(emm->alloca_buf, emm->alloca_buf_size, emm->heap_mem, max_chars); - if(!buf) + // rationale: see ErrorMessageMem + emm->pa_mem = page_aligned_alloc(message_size_bytes); + if(!emm->pa_mem) return L"(insufficient memory to generate error message)"; + wchar_t* const buf = (wchar_t*)emm->pa_mem; + const size_t max_chars = size_bytes / sizeof(wchar_t); wchar_t* pos = buf; size_t chars_left = max_chars; int len; // header @@ -700,8 +670,6 @@ ErrorReaction debug_display_error(const wchar_t* description, ErrorMessageMem emm; - emm.alloca_buf_size = 50000; - emm.alloca_buf = sys_alloca(emm.alloca_buf_size); const wchar_t* text = debug_error_message_build(description, fn_only, line, func, skip, context, &emm); diff --git a/source/lib/debug.h b/source/lib/debug.h index f73edc34dc..c329401509 100644 --- a/source/lib/debug.h +++ b/source/lib/debug.h @@ -650,12 +650,16 @@ extern const char* debug_get_thread_name(); **/ struct ErrorMessageMem { - // passed to debug_error_message_build from caller - void* alloca_buf; - size_t alloca_buf_size; - - // allocated within debug_error_message_build - void* heap_mem; + // rationale: + // - error messages with stack traces require a good deal of memory + // (dozens of KB). static buffers of that size are undesirable. + // - the heap may be corrupted, so don't use malloc. allocator.h's + // page_aligned_malloc (implemented via mmap) should be safe. + // - alloca is a bit iffy (the stack may be maxed out), non-portable and + // complicates the code because it can't be allocated by a subroutine. + // - this method is probably slow, but error messages aren't built often. + // if necessary, first try malloc and use mmap if that fails. + void* pa_mem; }; /** diff --git a/source/lib/lockfree.cpp b/source/lib/lockfree.cpp index 369e5f8087..1c253e17ff 100644 --- a/source/lib/lockfree.cpp +++ b/source/lib/lockfree.cpp @@ -284,7 +284,7 @@ static void smr_release_unreferenced_nodes(TLS* tls) retry: const size_t max_hps = (active_threads+3) * NUM_HPS; // allow for creating a few additional threads during the loop - void** hps = (void**)sys_alloca(max_hps * sizeof(void*)); + void** hps = (void**)alloca(max_hps * sizeof(void*)); size_t num_hps = 0; // for each participating thread: for(TLS* t = tls_list; t; t = t->next) @@ -561,7 +561,7 @@ retry: // or 0 if not found in the list. void* lfl_find(LFList* list, uintptr_t key) { - ListPos* pos = (ListPos*)sys_alloca(sizeof(ListPos)); + ListPos* pos = (ListPos*)alloca(sizeof(ListPos)); if(!list_lookup(list, key, pos)) return 0; return node_user_data(pos->cur); @@ -579,7 +579,7 @@ void* lfl_insert(LFList* list, uintptr_t key, size_t additional_bytes, int* was_ // if this triggers, tls_alloc called from lfl_init failed due to // lack of memory and the caller didn't check its return value. - ListPos* pos = (ListPos*)sys_alloca(sizeof(ListPos)); + ListPos* pos = (ListPos*)alloca(sizeof(ListPos)); Node* node = 0; if(was_inserted) @@ -632,7 +632,7 @@ LibError lfl_erase(LFList* list, uintptr_t key) // if this triggers, tls_alloc called from lfl_init failed due to // lack of memory and the caller didn't check its return value. - ListPos* pos = (ListPos*)sys_alloca(sizeof(ListPos)); + ListPos* pos = (ListPos*)alloca(sizeof(ListPos)); retry: // not found in list - abort. diff --git a/source/lib/sysdep/sysdep.h b/source/lib/sysdep/sysdep.h index 31b6040a55..04e4153351 100644 --- a/source/lib/sysdep/sysdep.h +++ b/source/lib/sysdep/sysdep.h @@ -106,11 +106,6 @@ extern LibError sys_cursor_free(void* cursor); extern int sys_vsnprintf(char* buffer, size_t count, const char* format, va_list argptr); -/** - * allocate on stack, automatically free when current function returns. - **/ -extern void* sys_alloca(size_t size); - // describe the current OS error state. // // err: if not 0, use that as the error code to translate; otherwise, diff --git a/source/lib/sysdep/win/wsysdep.cpp b/source/lib/sysdep/win/wsysdep.cpp index 24bdf8c32f..169ab30925 100644 --- a/source/lib/sysdep/win/wsysdep.cpp +++ b/source/lib/sysdep/win/wsysdep.cpp @@ -46,24 +46,6 @@ void sys_display_msgw(const wchar_t* caption, const wchar_t* msg) } -void* sys_alloca(size_t size) -{ - void* ret; - __try - { - ret = _alloca(size); - } - // if stack overflow, handle it; otherwise, continue handler search. - __except(GetExceptionCode() == STATUS_STACK_OVERFLOW) - { - // restore guard page - necessary on XP, works everywhere. - _resetstkoflw(); - ret = 0; - } - return ret; -} - - //----------------------------------------------------------------------------- // "program error" dialog (triggered by debug_assert and exception) //----------------------------------------------------------------------------- diff --git a/source/simulation/Scheduler.h b/source/simulation/Scheduler.h index f0d6491b03..c2e12a3f03 100644 --- a/source/simulation/Scheduler.h +++ b/source/simulation/Scheduler.h @@ -12,7 +12,6 @@ #include #include -#include "EntityMessage.h" #include "EntityHandles.h" #include "ps/Singleton.h" #include "ps/CStr.h"