From f330bde8aae1c8667fbc71ae56285b74faa112b3 Mon Sep 17 00:00:00 2001 From: Martins Mozeiko Date: Fri, 16 Jan 2026 16:40:30 -0800 Subject: [PATCH] better callstack for null calls This improves callstack in win32 unhandled exception handler when indirect call to NULL happens. Before no call stack was printed at all, so it was hard to know what happened. Now call stack explicitly will print out [NULL] stack entry + rest of call stack entries. This is done by manually looking up return address from call stack when possible. Also fixes wine compatibility for os_commit function. Wine does not support RIO buffer functions. --- src/os/core/win32/os_core_win32.c | 58 +++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 6e681f0e..8aaf0fda 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -208,7 +208,11 @@ internal B32 os_commit(void *ptr, U64 size) { B32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0); - w32_rio_functions.RIODeregisterBuffer(w32_rio_functions.RIORegisterBuffer(ptr, size)); + if (w32_rio_functions.RIORegisterBuffer) + { + // wine does not implement these functions + w32_rio_functions.RIODeregisterBuffer(w32_rio_functions.RIORegisterBuffer(ptr, size)); + } return result; } @@ -1565,7 +1569,43 @@ win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) #else # error Arch not supported! #endif - + +#if BUILD_CONSOLE_INTERFACE + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\nCreate a new issue with this report at %S.\n\n", BUILD_ISSUES_LINK_STRING_LITERAL); +#else + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, + L"\nPress Ctrl+C to copy this text to clipboard, then create a new issue at\n" + L"%S\n\n", BUILD_ISSUES_LINK_STRING_LITERAL, BUILD_ISSUES_LINK_STRING_LITERAL); +#endif + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"Call stack:\n"); + + U64 frame_offset = 0; + + if (frame.AddrPC.Offset == 0) + { + // if IP address is 0 then most likely we have called indirectly on NULL function pointer + // which means no useful stack unwinding will happen, because there's no unwind info for address 0 + // but we can try reading 8 bytes of return address from stack, and start unwinding there + + ULONG_PTR hi, lo; + GetCurrentThreadStackLimits(&lo, &hi); + if (frame.AddrStack.Offset >= lo && frame.AddrStack.Offset <= hi - sizeof(void*)) + { + frame.AddrPC.Offset = *(DWORD64*)frame.AddrStack.Offset - 1; + frame.AddrStack.Offset += sizeof(void*); +#if defined(_M_AMD64) + context->Rip = frame.AddrPC.Offset; + context->Rsp = frame.AddrStack.Offset; +#elif defined(_M_ARM64) + context->Pc = frame.AddrPC.Offset; + context->Sp = frame.AddrStack.Offset; +#endif + } + + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"1. [NULL]\n"); + frame_offset = 1; + } + for(U32 idx=0; ;idx++) { const U32 max_frames = 32; @@ -1586,19 +1626,7 @@ win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) break; } - if(idx==0) - { -#if BUILD_CONSOLE_INTERFACE - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\nCreate a new issue with this report at %S.\n\n", BUILD_ISSUES_LINK_STRING_LITERAL); -#else - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, - L"\nPress Ctrl+C to copy this text to clipboard, then create a new issue at\n" - L"%S\n\n", BUILD_ISSUES_LINK_STRING_LITERAL, BUILD_ISSUES_LINK_STRING_LITERAL); -#endif - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"Call stack:\n"); - } - - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"%u. [0x%I64x]", idx + 1, address); + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"%u. [0x%I64x]", frame_offset + idx + 1, address); struct { SYMBOL_INFOW info;