From 29dd43d5ab18ec01df0d173e974d261afd16a311 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 2 May 2022 18:52:51 -0700 Subject: FatalSignalHandler: remember the previous signal's handler And only restore those signals, instead of iterating over all possible signals, instead of attempting to restore to SIG_DFL. Also, as a consequence, we will install our handler even if there was already a handler installed for the signal. Pick-to: 6.3 Change-Id: I5ff8e16fcdcb4ffd9ab6fffd16eb756685f4e8b8 Reviewed-by: Edward Welbourne Reviewed-by: Marc Mutz --- src/testlib/qtestcase.cpp | 64 +++++++++++++++++------------------------------ 1 file changed, 23 insertions(+), 41 deletions(-) (limited to 'src/testlib/qtestcase.cpp') diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 122c85ff27..7dbe13bb6d 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1836,16 +1836,19 @@ using FatalSignalHandler = WindowsFaultHandler; class FatalSignalHandler { public: + static constexpr std::array fatalSignals = { + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGPIPE, SIGTERM + }; + using OldActionsArray = std::array; + FatalSignalHandler() { pauseOnCrash = qEnvironmentVariableIsSet("QTEST_PAUSE_ON_CRASH"); - sigemptyset(&handledSignals); - - const int fatalSignals[] = { - SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGPIPE, SIGTERM }; - struct sigaction act; memset(&act, 0, sizeof(act)); + act.sa_handler = SIG_DFL; + oldActions().fill(act); + // Remove the handler after it is invoked. act.sa_flags = SA_RESETHAND; @@ -1882,39 +1885,14 @@ public: for (int signal : fatalSignals) sigaddset(&act.sa_mask, signal); - // The destructor can only restore SIG_DFL, so only register for signals - // that had default handling previously. - const auto isDefaultHandler = [](const struct sigaction &old) { -# ifdef SA_SIGINFO - // void sa_sigaction(int, siginfo_t *, void *) is never the default: - if (old.sa_flags & SA_SIGINFO) - return false; -# endif - // Otherwise, the handler is void sa_handler(int) but may be - // SIG_DFL (default action) or SIG_IGN (ignore signal): - return old.sa_handler == SIG_DFL; - }; - - struct sigaction oldact; - for (int signal : fatalSignals) { - // Registering reveals the existing handler: - if (sigaction(signal, &act, &oldact)) - continue; // Failed to set our handler; nothing to restore. - if (isDefaultHandler(oldact)) - sigaddset(&handledSignals, signal); - else // Restore non-default handler: - sigaction(signal, &oldact, nullptr); - } + for (size_t i = 0; i < fatalSignals.size(); ++i) + sigaction(fatalSignals[i], &act, &oldActions()[i]); } ~FatalSignalHandler() { - // Restore the default signal handler in place of ours. + // Restore the default signal handlers in place of ours. // If ours has been replaced, leave the replacement alone. - struct sigaction act; - memset(&act, 0, sizeof(act)); - act.sa_handler = SIG_DFL; - auto isOurs = [](const struct sigaction &old) { # ifdef SA_SIGINFO return (old.sa_flags & SA_SIGINFO) && old.sa_sigaction == FatalSignalHandler::actionHandler; @@ -1924,20 +1902,26 @@ public: }; struct sigaction action; - for (int signum = 1; signum < 32; ++signum) { - if (!sigismember(&handledSignals, signum)) - continue; - if (sigaction(signum, nullptr, &action)) + for (size_t i = 0; i < fatalSignals.size(); ++i) { + struct sigaction &act = oldActions()[i]; + if (act.sa_flags == 0 && act.sa_handler == SIG_DFL) + continue; // Already the default + if (sigaction(fatalSignals[i], nullptr, &action)) continue; // Failed to query present handler - if (isOurs(action)) - sigaction(signum, &act, nullptr); + sigaction(fatalSignals[i], &act, nullptr); } } private: Q_DISABLE_COPY_MOVE(FatalSignalHandler) + static OldActionsArray &oldActions() + { + Q_CONSTINIT static OldActionsArray oldActions {}; + return oldActions; + } + static void actionHandler(int signum, siginfo_t * /* info */, void * /* ucontext */) { const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime()); @@ -1961,8 +1945,6 @@ private: { actionHandler(signum, nullptr, nullptr); } - - sigset_t handledSignals; static bool pauseOnCrash; }; bool FatalSignalHandler::pauseOnCrash = false; -- cgit v1.2.3