From 8699e1887c6549280af812aa7188b121d9ba5d05 Mon Sep 17 00:00:00 2001 From: SChernykh Date: Tue, 7 Nov 2023 10:34:42 +0100 Subject: [PATCH] Debug: print call stack of unhandled exceptions --- .github/workflows/cppcheck.yml | 4 +- src/log.cpp | 69 +++++++++++++++++++++++++++++++++- src/memory_leak_debug.cpp | 6 +-- 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml index 4a3cc7f..52eb424 100644 --- a/.github/workflows/cppcheck.yml +++ b/.github/workflows/cppcheck.yml @@ -15,7 +15,7 @@ on: jobs: cppcheck-ubuntu: - timeout-minutes: 50 + timeout-minutes: 60 runs-on: ubuntu-latest steps: @@ -60,7 +60,7 @@ jobs: cppcheck-windows: - timeout-minutes: 50 + timeout-minutes: 60 runs-on: windows-latest steps: diff --git a/src/log.cpp b/src/log.cpp index c08fed0..f946504 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -44,8 +44,64 @@ bool CONSOLE_COLORS = true; #ifdef _WIN32 static const HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); static const HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); -static const HANDLE hStdErr = GetStdHandle(STD_ERROR_HANDLE); -#endif + +#if defined(_MSC_VER) && !defined(NDEBUG) + +#include + +#pragma comment(lib, "Dbghelp.lib") + +LONG WINAPI UnhandledExceptionFilter(_In_ _EXCEPTION_POINTERS*) +{ + constexpr size_t MAX_FRAMES = 32; + + void* stack_trace[MAX_FRAMES] = {}; + DWORD hash; + CaptureStackBackTrace(1, MAX_FRAMES, stack_trace, &hash); + + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = {}; + PSYMBOL_INFO pSymbol = reinterpret_cast(buffer); + + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + IMAGEHLP_LINE64 line{}; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + const HANDLE h = GetCurrentProcess(); + + fprintf(stderr, "\n\nUnhandled exception at:\n"); + fflush(stderr); + + for (size_t j = 0; j < MAX_FRAMES; ++j) { + const DWORD64 address = reinterpret_cast(stack_trace[j]); + DWORD t = 0; + if (SymFromAddr(h, address, nullptr, pSymbol) && SymGetLineFromAddr64(h, address, &t, &line)) { + fprintf(stderr, "%s (%s, line %lu)\n", line.FileName, pSymbol->Name, line.LineNumber); + fflush(stderr); + } + } + + fprintf(stderr, "\n\n"); + fflush(stderr); + + // Normal logging might be broken at this point, but try to log it anyway + LOGERR(0, "Unhandled exception at:"); + + for (size_t j = 0; j < MAX_FRAMES; ++j) { + const DWORD64 address = reinterpret_cast(stack_trace[j]); + DWORD t = 0; + if (SymFromAddr(h, address, nullptr, pSymbol) && SymGetLineFromAddr64(h, address, &t, &line)) { + LOGERR(0, line.FileName << " (" << static_cast(pSymbol->Name) << ", line " << static_cast(line.LineNumber) << ')'); + } + } + + Sleep(1000); + + return EXCEPTION_CONTINUE_SEARCH; +} +#endif // _MSC_VER && !NDEBUG +#endif // _WIN32 class Worker { @@ -62,6 +118,11 @@ public: , m_started{ false } , m_stopped(false) { +#if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG) + SetUnhandledExceptionFilter(UnhandledExceptionFilter); + SymInitialize(GetCurrentProcess(), NULL, TRUE); +#endif + set_main_thread(); std::setlocale(LC_ALL, "en_001"); @@ -140,6 +201,10 @@ public: #endif m_logFile.close(); + +#if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG) + SymCleanup(GetCurrentProcess()); +#endif } FORCEINLINE void write(const char* buf, uint32_t size) diff --git a/src/memory_leak_debug.cpp b/src/memory_leak_debug.cpp index 05a8f89..0aef9d7 100644 --- a/src/memory_leak_debug.cpp +++ b/src/memory_leak_debug.cpp @@ -18,7 +18,7 @@ #include "common.h" // Simple memory leak detector for Windows users, works best in RelWithDebInfo configuration. -#if defined(_WIN32) && defined(DEV_TRACK_MEMORY) +#if defined(_WIN32) && defined(DEV_TRACK_MEMORY) && defined(_MSC_VER) && !defined(NDEBUG) #include "uv_util.h" #include @@ -270,8 +270,6 @@ void memory_tracking_start() // Trigger std::ostream initialization to avoid reporting it as leaks std::cout << "Memory leak detection = " << 1 << std::endl; - SymInitialize(GetCurrentProcess(), NULL, TRUE); - using namespace p2pool; uv_replace_allocator(malloc_hook, realloc_hook, calloc_hook, free_hook); @@ -307,8 +305,6 @@ bool memory_tracking_stop() printf("No memory leaks detected\n\n"); } - SymCleanup(h); - return (total_leaks == 0); }