Adapt QTest::FatalSignalHandler() to support sa_sigaction when available

We don't currently have a use for the extra parameters, but Samuel
Mira's fix to ensure we don't miss fatal signals on Android needs to
be able to call the prior handler, which may need these parameters.

In the process, check returns from sigaction() and use its nullptr
semantics to query first when detecting whether to restore the default
when done, rather than setting and then restoring if it turns out
we've been replaced in the meantime.

Task-number: QTBUG-97652
Pick-to: 6.2 6.3
Change-Id: If30a0db35946c3dceb409ae3f41aa437149472e6
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2022-02-25 12:38:37 +01:00
parent 6782a37bb5
commit fcecaf53f5

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
@ -1692,7 +1692,12 @@ public:
struct sigaction act;
memset(&act, 0, sizeof(act));
# ifdef SA_SIGINFO
act.sa_flags |= SA_SIGINFO;
act.sa_sigaction = FatalSignalHandler::signal;
# else
act.sa_handler = FatalSignalHandler::signal;
# endif
// Remove the handler after it is invoked.
# if !defined(Q_OS_INTEGRITY)
@ -1754,21 +1759,29 @@ public:
~FatalSignalHandler()
{
#if defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
// Unregister any of our remaining signal handlers
// Restore the default signal handler 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::signal;
# else
return old.sa_handler == FatalSignalHandler::signal;
# endif
};
struct sigaction oldact;
for (int i = 1; i < 32; ++i) {
if (!sigismember(&handledSignals, i))
continue;
sigaction(i, &act, &oldact);
if (sigaction(i, nullptr, &oldact))
continue; // Failed to query present handler
// If someone overwrote it in the mean time, put it back
if (oldact.sa_handler != FatalSignalHandler::signal)
sigaction(i, &oldact, nullptr);
if (isOurs(oldact))
sigaction(i, &act, nullptr);
}
#endif
}
@ -1820,7 +1833,11 @@ private:
#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
static void signal(int signum)
#endif
{
const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime());
const int msecsTotalTime = qRound(QTestLog::msecsTotalTime());