From 3bd1aa09b62684cb7b715d5d5d5a6def20f27597 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 2 May 2022 18:22:11 -0700 Subject: [PATCH] FatalSignalHandler: split the Windows and Unix contents They're very different, so there's no point in having them even in the same class body. I've renamed the Windows one because Windows does not report crashes via signals anyway. If you have an IDE that can scan both branches of the #if, it will help you find the Windows-specific code too. Pick-to: 6.3 Change-Id: I5ff8e16fcdcb4ffd9ab6fffd16eb73ba196cfb74 Reviewed-by: Marc Mutz --- src/testlib/qtestcase.cpp | 115 +++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index ca906f6d2ba..8c40d111b84 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1771,20 +1771,70 @@ DebugSymbolResolver::Symbol DebugSymbolResolver::resolveSymbol(DWORD64 address) return result; } -#endif // Q_OS_WIN - -class FatalSignalHandler +class WindowsFaultHandler { public: - FatalSignalHandler() + WindowsFaultHandler() { -#if defined(Q_OS_WIN) # if !defined(Q_CC_MINGW) _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); # endif SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX); SetUnhandledExceptionFilter(windowsFaultHandler); + } + +private: + static LONG WINAPI windowsFaultHandler(struct _EXCEPTION_POINTERS *exInfo) + { + enum { maxStackFrames = 100 }; + char appName[MAX_PATH]; + if (!GetModuleFileNameA(NULL, appName, MAX_PATH)) + appName[0] = 0; + const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime()); + const int msecsTotalTime = qRound(QTestLog::msecsTotalTime()); + const void *exceptionAddress = exInfo->ExceptionRecord->ExceptionAddress; + printf("A crash occurred in %s.\n" + "Function time: %dms Total time: %dms\n\n" + "Exception address: 0x%p\n" + "Exception code : 0x%lx\n", + appName, msecsFunctionTime, msecsTotalTime, + exceptionAddress, exInfo->ExceptionRecord->ExceptionCode); + + DebugSymbolResolver resolver(GetCurrentProcess()); + if (resolver.isValid()) { + DebugSymbolResolver::Symbol exceptionSymbol = resolver.resolveSymbol(DWORD64(exceptionAddress)); + if (exceptionSymbol.name) { + printf("Nearby symbol : %s\n", exceptionSymbol.name); + delete [] exceptionSymbol.name; + } + void *stack[maxStackFrames]; + fputs("\nStack:\n", stdout); + const unsigned frameCount = CaptureStackBackTrace(0, DWORD(maxStackFrames), stack, NULL); + for (unsigned f = 0; f < frameCount; ++f) { + DebugSymbolResolver::Symbol symbol = resolver.resolveSymbol(DWORD64(stack[f])); + if (symbol.name) { + printf("#%3u: %s() - 0x%p\n", f + 1, symbol.name, (const void *)symbol.address); + delete [] symbol.name; + } else { + printf("#%3u: Unable to obtain symbol\n", f + 1); + } + } + } + + fputc('\n', stdout); + fflush(stdout); + + return EXCEPTION_EXECUTE_HANDLER; + } +}; +using FatalSignalHandler = WindowsFaultHandler; + #elif defined(Q_OS_UNIX) && !defined(Q_OS_WASM) +class FatalSignalHandler +{ +public: + FatalSignalHandler() + { pauseOnCrash = qEnvironmentVariableIsSet("QTEST_PAUSE_ON_CRASH"); sigemptyset(&handledSignals); @@ -1854,12 +1904,10 @@ public: else // Restore non-default handler: sigaction(signal, &oldact, nullptr); } -#endif // defined(Q_OS_UNIX) && !defined(Q_OS_WASM) } ~FatalSignalHandler() { -#if defined(Q_OS_UNIX) && !defined(Q_OS_WASM) // Restore the default signal handler in place of ours. // If ours has been replaced, leave the replacement alone. struct sigaction act; @@ -1884,56 +1932,9 @@ public: if (isOurs(action)) sigaction(signum, &act, nullptr); } -#endif } private: -#if defined(Q_OS_WIN) - static LONG WINAPI windowsFaultHandler(struct _EXCEPTION_POINTERS *exInfo) - { - enum { maxStackFrames = 100 }; - char appName[MAX_PATH]; - if (!GetModuleFileNameA(NULL, appName, MAX_PATH)) - appName[0] = 0; - const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime()); - const int msecsTotalTime = qRound(QTestLog::msecsTotalTime()); - const void *exceptionAddress = exInfo->ExceptionRecord->ExceptionAddress; - printf("A crash occurred in %s.\n" - "Function time: %dms Total time: %dms\n\n" - "Exception address: 0x%p\n" - "Exception code : 0x%lx\n", - appName, msecsFunctionTime, msecsTotalTime, - exceptionAddress, exInfo->ExceptionRecord->ExceptionCode); - - DebugSymbolResolver resolver(GetCurrentProcess()); - if (resolver.isValid()) { - DebugSymbolResolver::Symbol exceptionSymbol = resolver.resolveSymbol(DWORD64(exceptionAddress)); - if (exceptionSymbol.name) { - printf("Nearby symbol : %s\n", exceptionSymbol.name); - delete [] exceptionSymbol.name; - } - void *stack[maxStackFrames]; - fputs("\nStack:\n", stdout); - const unsigned frameCount = CaptureStackBackTrace(0, DWORD(maxStackFrames), stack, NULL); - for (unsigned f = 0; f < frameCount; ++f) { - DebugSymbolResolver::Symbol symbol = resolver.resolveSymbol(DWORD64(stack[f])); - if (symbol.name) { - printf("#%3u: %s() - 0x%p\n", f + 1, symbol.name, (const void *)symbol.address); - delete [] symbol.name; - } else { - printf("#%3u: Unable to obtain symbol\n", f + 1); - } - } - } - - fputc('\n', stdout); - fflush(stdout); - - return EXCEPTION_EXECUTE_HANDLER; - } -#endif // defined(Q_OS_WIN) - -#if defined(Q_OS_UNIX) && !defined(Q_OS_WASM) # ifdef SA_SIGINFO static void signal(int signum, siginfo_t * /* info */, void * /* ucontext */) # else @@ -1967,11 +1968,11 @@ private: sigset_t handledSignals; static bool pauseOnCrash; -#endif // defined(Q_OS_UNIX) && !defined(Q_OS_WASM) }; -#if defined(Q_OS_UNIX) && !defined(Q_OS_WASM) bool FatalSignalHandler::pauseOnCrash = false; -#endif // defined(Q_OS_UNIX) && !defined(Q_OS_WASM) +#else // Q_OS_WASM or weird systems +class FatalSignalHandler {}; +#endif // Q_OS_* choice } // unnamed namespace