From 3d9e56aa6cc20a5a0822877e86a43e9a0affb503 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 2 May 2022 19:28:04 -0700 Subject: FatalSignalHandler: chain back to the original crash handler If a previous handler was already installed, ensure it is called, because there may be a reason why it was there. For example, the Android ART adds a signal action to every fatal signal for logging purposes. We do that by restoring the signal handler we had and re-raising the signal. If our handler was overridden by something else, then that handler was already called, but will get uninstalled after our code runs. It won't be a problem, because the application is exiting anyway. [ChangeLog][QtTest][Behavior Change] On Unix, the QtTest code to handle Unix/POSIX fatal signals will now call back to the original handler that was installed, if there was one. This allows logging frameworks (such as Android ART's), for example, to log the crash too. Additionally, if there was no handler, the application should exit with the correct signal instead of SIGABRT. Fixes: QTBUG-97652 Pick-to: 6.3 Change-Id: Ifc4fca159b490d8d0b614d736e46caefcb903a4c Reviewed-by: Marc Mutz Reviewed-by: Edward Welbourne --- src/testlib/qtestcase.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src') diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 7dbe13bb6d..b06c88b6cb 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1839,6 +1839,15 @@ public: static constexpr std::array fatalSignals = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGPIPE, SIGTERM }; + static constexpr std::array crashingSignals = { + // Crash signals are special, because if we return from the handler + // without adjusting the machine state, the same instruction that + // originally caused the crash will get re-executed and will thus cause + // the same crash again. This is useful if our parent process logs the + // exit result or if core dumps are enabled: the core file will point + // to the actual instruction that crashed. + SIGILL, SIGBUS, SIGFPE, SIGSEGV + }; using OldActionsArray = std::array; FatalSignalHandler() @@ -1938,6 +1947,28 @@ private: writeToStderr("Received signal ", asyncSafeToString(signum), "\n Function time: ", asyncSafeToString(msecsFunctionTime), "ms Total time: ", asyncSafeToString(msecsTotalTime), "ms\n"); + + bool isCrashingSignal = + std::find(crashingSignals.begin(), crashingSignals.end(), signum) != crashingSignals.end(); + + // chain back to the previous handler, if any + for (size_t i = 0; i < fatalSignals.size(); ++i) { + struct sigaction &act = oldActions()[i]; + if (signum != fatalSignals[i]) + continue; + + // restore the handler (if SA_RESETHAND hasn't done the job for us) + if (SA_RESETHAND == 0 || act.sa_handler != SIG_DFL || act.sa_flags) + (void) sigaction(signum, &act, nullptr); + + if (!isCrashingSignal) + raise(signum); + + // signal is blocked, so it'll be delivered when we return + return; + } + + // we shouldn't reach here! std::abort(); } -- cgit v1.2.3