summaryrefslogtreecommitdiffstats
path: root/src/testlib/qtestcase.cpp
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2020-01-31 20:34:27 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2020-02-01 10:43:52 +0100
commit0c8ff269dcda7de68c475535d575c0bb34af788b (patch)
tree63f10f629dc39d4f523172b99b52a6c506aebc73 /src/testlib/qtestcase.cpp
parentd005d743dea1b072fdd18507f7bf6170f5e3d7ab (diff)
testlib: Unite Windows and Unix signal handler code
Change-Id: I7b9d480008167c071bf925d655eb97ef437bc206 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/testlib/qtestcase.cpp')
-rw-r--r--src/testlib/qtestcase.cpp330
1 files changed, 165 insertions, 165 deletions
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index fde20ada33..372e208919 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -1533,121 +1533,6 @@ void TestMethods::invokeTests(QObject *testObject) const
QTestResult::setCurrentTestFunction(nullptr);
}
-#if defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
-
-class FatalSignalHandler
-{
-public:
- FatalSignalHandler()
- {
- sigemptyset(&handledSignals);
-
- const int fatalSignals[] = {
- SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGPIPE, SIGTERM, 0 };
-
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_handler = FatalSignalHandler::signal;
-
- // Remove the handler after it is invoked.
-#if !defined(Q_OS_INTEGRITY)
- act.sa_flags = SA_RESETHAND;
-#endif
-
- // tvOS/watchOS both define SA_ONSTACK (in sys/signal.h) but mark sigaltstack() as
- // unavailable (__WATCHOS_PROHIBITED __TVOS_PROHIBITED in signal.h)
-#if defined(SA_ONSTACK) && !defined(Q_OS_TVOS) && !defined(Q_OS_WATCHOS)
- // Let the signal handlers use an alternate stack
- // This is necessary if SIGSEGV is to catch a stack overflow
-# if defined(Q_CC_GNU) && defined(Q_OF_ELF)
- // Put the alternate stack in the .lbss (large BSS) section so that it doesn't
- // interfere with normal .bss symbols
- __attribute__((section(".lbss.altstack"), aligned(4096)))
-# endif
- static char alternate_stack[16 * 1024];
- stack_t stack;
- stack.ss_flags = 0;
- stack.ss_size = sizeof alternate_stack;
- stack.ss_sp = alternate_stack;
- sigaltstack(&stack, nullptr);
- act.sa_flags |= SA_ONSTACK;
-#endif
-
- // Block all fatal signals in our signal handler so we don't try to close
- // the testlog twice.
- sigemptyset(&act.sa_mask);
- for (int i = 0; fatalSignals[i]; ++i)
- sigaddset(&act.sa_mask, fatalSignals[i]);
-
- struct sigaction oldact;
-
- for (int i = 0; fatalSignals[i]; ++i) {
- sigaction(fatalSignals[i], &act, &oldact);
- if (
-#ifdef SA_SIGINFO
- oldact.sa_flags & SA_SIGINFO ||
-#endif
- oldact.sa_handler != SIG_DFL) {
- sigaction(fatalSignals[i], &oldact, nullptr);
- } else
- {
- sigaddset(&handledSignals, fatalSignals[i]);
- }
- }
- }
-
- ~FatalSignalHandler()
- {
- // Unregister any of our remaining signal handlers
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_handler = SIG_DFL;
-
- struct sigaction oldact;
-
- for (int i = 1; i < 32; ++i) {
- if (!sigismember(&handledSignals, i))
- continue;
- sigaction(i, &act, &oldact);
-
- // If someone overwrote it in the mean time, put it back
- if (oldact.sa_handler != FatalSignalHandler::signal)
- sigaction(i, &oldact, nullptr);
- }
- }
-
-private:
- static void signal(int signum)
- {
- const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime());
- const int msecsTotalTime = qRound(QTestLog::msecsTotalTime());
- if (signum != SIGINT) {
- stackTrace();
- if (qEnvironmentVariableIsSet("QTEST_PAUSE_ON_CRASH")) {
- fprintf(stderr, "Pausing process %d for debugging\n", getpid());
- raise(SIGSTOP);
- }
- }
- qFatal("Received signal %d\n"
- " Function time: %dms Total time: %dms",
- signum, msecsFunctionTime, msecsTotalTime);
-#if defined(Q_OS_INTEGRITY)
- {
- struct sigaction act;
- memset(&act, 0, sizeof(struct sigaction));
- act.sa_handler = SIG_DFL;
- sigaction(signum, &act, NULL);
- }
-#endif
- }
-
- sigset_t handledSignals;
-};
-
-#endif
-
-} // namespace
-
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
// Helper class for resolving symbol names by dynamically loading "dbghelp.dll".
@@ -1746,49 +1631,177 @@ DebugSymbolResolver::Symbol DebugSymbolResolver::resolveSymbol(DWORD64 address)
return result;
}
-static LONG WINAPI windowsFaultHandler(struct _EXCEPTION_POINTERS *exInfo)
+#endif // Q_OS_WIN && !Q_OS_WINRT
+
+class FatalSignalHandler
{
- 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;
+public:
+ FatalSignalHandler()
+ {
+#if defined(Q_OS_WIN)
+# if !defined(Q_CC_MINGW)
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
+# endif
+# if !defined(Q_OS_WINRT)
+ SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX);
+ SetUnhandledExceptionFilter(windowsFaultHandler);
+# endif
+#elif defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
+ sigemptyset(&handledSignals);
+
+ const int fatalSignals[] = {
+ SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGPIPE, SIGTERM, 0 };
+
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = FatalSignalHandler::signal;
+
+ // Remove the handler after it is invoked.
+# if !defined(Q_OS_INTEGRITY)
+ act.sa_flags = SA_RESETHAND;
+# endif
+
+ // tvOS/watchOS both define SA_ONSTACK (in sys/signal.h) but mark sigaltstack() as
+ // unavailable (__WATCHOS_PROHIBITED __TVOS_PROHIBITED in signal.h)
+# if defined(SA_ONSTACK) && !defined(Q_OS_TVOS) && !defined(Q_OS_WATCHOS)
+ // Let the signal handlers use an alternate stack
+ // This is necessary if SIGSEGV is to catch a stack overflow
+# if defined(Q_CC_GNU) && defined(Q_OF_ELF)
+ // Put the alternate stack in the .lbss (large BSS) section so that it doesn't
+ // interfere with normal .bss symbols
+ __attribute__((section(".lbss.altstack"), aligned(4096)))
+# endif
+ static char alternate_stack[16 * 1024];
+ stack_t stack;
+ stack.ss_flags = 0;
+ stack.ss_size = sizeof alternate_stack;
+ stack.ss_sp = alternate_stack;
+ sigaltstack(&stack, nullptr);
+ act.sa_flags |= SA_ONSTACK;
+# endif
+
+ // Block all fatal signals in our signal handler so we don't try to close
+ // the testlog twice.
+ sigemptyset(&act.sa_mask);
+ for (int i = 0; fatalSignals[i]; ++i)
+ sigaddset(&act.sa_mask, fatalSignals[i]);
+
+ struct sigaction oldact;
+
+ for (int i = 0; fatalSignals[i]; ++i) {
+ sigaction(fatalSignals[i], &act, &oldact);
+ if (
+# ifdef SA_SIGINFO
+ oldact.sa_flags & SA_SIGINFO ||
+# endif
+ oldact.sa_handler != SIG_DFL) {
+ sigaction(fatalSignals[i], &oldact, nullptr);
+ } else
+ {
+ sigaddset(&handledSignals, fatalSignals[i]);
+ }
}
- 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);
+#endif // defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
+ }
+
+ ~FatalSignalHandler()
+ {
+#if defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
+ // Unregister any of our remaining signal handlers
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_DFL;
+
+ struct sigaction oldact;
+
+ for (int i = 1; i < 32; ++i) {
+ if (!sigismember(&handledSignals, i))
+ continue;
+ sigaction(i, &act, &oldact);
+
+ // If someone overwrote it in the mean time, put it back
+ if (oldact.sa_handler != FatalSignalHandler::signal)
+ sigaction(i, &oldact, nullptr);
+ }
+#endif
+ }
+
+private:
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ 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) && !defined(Q_OS_WINRT)
- fputc('\n', stdout);
- fflush(stdout);
+#if defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
+ static void signal(int signum)
+ {
+ const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime());
+ const int msecsTotalTime = qRound(QTestLog::msecsTotalTime());
+ if (signum != SIGINT) {
+ stackTrace();
+ if (qEnvironmentVariableIsSet("QTEST_PAUSE_ON_CRASH")) {
+ fprintf(stderr, "Pausing process %d for debugging\n", getpid());
+ raise(SIGSTOP);
+ }
+ }
+ qFatal("Received signal %d\n"
+ " Function time: %dms Total time: %dms",
+ signum, msecsFunctionTime, msecsTotalTime);
+# if defined(Q_OS_INTEGRITY)
+ {
+ struct sigaction act;
+ memset(&act, 0, sizeof(struct sigaction));
+ act.sa_handler = SIG_DFL;
+ sigaction(signum, &act, NULL);
+ }
+# endif
+ }
- return EXCEPTION_EXECUTE_HANDLER;
-}
-#endif // Q_OS_WIN) && !Q_OS_WINRT
+ sigset_t handledSignals;
+#endif // defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
+};
+
+} // namespace
static void initEnvironment()
{
@@ -1896,18 +1909,6 @@ int QTest::qRun()
try {
#endif
-#if defined(Q_OS_WIN)
- if (!noCrashHandler) {
-# ifndef Q_CC_MINGW
- _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
-# endif
-# ifndef Q_OS_WINRT
- SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX);
- SetUnhandledExceptionFilter(windowsFaultHandler);
-# endif
- } // !noCrashHandler
-#endif // Q_OS_WIN
-
#if QT_CONFIG(valgrind)
if (QBenchmarkGlobalData::current->mode() == QBenchmarkGlobalData::CallgrindParentProcess) {
if (Q_UNLIKELY(!qApp))
@@ -1922,11 +1923,10 @@ int QTest::qRun()
} else
#endif
{
-#if defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
QScopedPointer<FatalSignalHandler> handler;
if (!noCrashHandler)
handler.reset(new FatalSignalHandler);
-#endif
+
TestMethods::MetaMethods commandLineMethods;
for (const QString &tf : qAsConst(QTest::testFunctions)) {
const QByteArray tfB = tf.toLatin1();