From aab4aa0e4676a77cf27d61c4cbb78dcf8fd2e6a9 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 3 May 2022 20:05:49 -0700 Subject: [PATCH] FatalSignalHandler: print some more information from siginfo_t The siginfo_t parameter allows us to show what process sent a signal or the crashing address. Additionally, it allows us to determine if the crashing signal was indeed sent due to a crash. The selftest tst_crashes produces now: $ QTEST_DISABLE_STACK_DUMP=1 ./crashes ********* Start testing of tst_Crashes ********* Config: Using QtTest library 6.4.0, Qt 6.4.0 (x86_64-little_endian-lp64 shared (dynamic) debug build; by GCC 11.2.1 20220420 [revision 691af15031e00227ba6d5935c1d737026cda4129]), opensuse-tumbleweed 20220428 PASS : tst_Crashes::initTestCase() Received signal 11 (SIGSEGV), code 1, for address 0x0000000000000004 Function time: 0ms, total time: 0ms [1] 201995 segmentation fault (core dumped) QTEST_DISABLE_STACK_DUMP=1 ./crashes The last line comes from the shell. The code isn't decoded, but on Linux it's a SEGV_MAPERR. macOS prints exactly the same thing. I've updated one of the expected_crashes_*.txt output that doesn't seem possible (the "Received a fatal error" message does not appear in Qt anywhere). Change-Id: I5ff8e16fcdcb4ffd9ab6fffd16ebc8391234f0e2 Reviewed-by: Volker Hilsheimer (cherry picked from commit 5e67e7efaa2669252fd8c55392b7bc35b72c6079) Reviewed-by: Qt Cherry-pick Bot --- src/testlib/qtestcase.cpp | 45 ++++++++++++++++--- .../testlib/selftests/expected_crashes_3.txt | 7 +-- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 6b5584366d4..f55d4ba38f9 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -2074,12 +2074,48 @@ private: # endif } - static void actionHandler(int signum, siginfo_t * /* info */, void * /* ucontext */) + template static + std::enable_if_t().si_pid) + sizeof(std::declval().si_uid) >= 1> + printSentSignalInfo(T *info) + { + writeToStderr(" sent by PID ", asyncSafeToString(info->si_pid), + " UID ", asyncSafeToString(info->si_uid)); + } + static void printSentSignalInfo(...) {} + + template static + std::enable_if_t().si_addr) >= 1> printCrashingSignalInfo(T *info) + { + using HexString = std::array; + auto toHexString = [](quintptr u, HexString &&r = {}) { + int shift = sizeof(quintptr) * 8 - 4; + for (size_t i = 0; i < sizeof(quintptr) * 2; ++i, shift -= 4) + r[i] = QtMiscUtils::toHexLower(u >> shift); + struct iovec vec; + vec.iov_base = r.data(); + vec.iov_len = r.size(); + return vec; + }; + writeToStderr(", code ", asyncSafeToString(info->si_code), + ", for address 0x", toHexString(quintptr(info->si_addr))); + } + static void printCrashingSignalInfo(...) {} + + static void actionHandler(int signum, siginfo_t *info, void * /* ucontext */) { writeToStderr("Received signal ", asyncSafeToString(signum), - " (SIG", signalName(signum), ")\n"); - printTestRunTime(); + " (SIG", signalName(signum), ")"); + bool isCrashingSignal = + std::find(crashingSignals.begin(), crashingSignals.end(), signum) != crashingSignals.end(); + if (isCrashingSignal && (!info || info->si_code <= 0)) + isCrashingSignal = false; // wasn't sent by the kernel, so it's not really a crash + if (isCrashingSignal) + printCrashingSignalInfo(info); + else if (info && (info->si_code == SI_USER || info->si_code == SI_QUEUE)) + printSentSignalInfo(info); + + printTestRunTime(); if (signum != SIGINT) { generateStackTrace(); if (pauseOnCrash) { @@ -2089,9 +2125,6 @@ private: } } - 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]; diff --git a/tests/auto/testlib/selftests/expected_crashes_3.txt b/tests/auto/testlib/selftests/expected_crashes_3.txt index c32ea536752..b0d69009d15 100644 --- a/tests/auto/testlib/selftests/expected_crashes_3.txt +++ b/tests/auto/testlib/selftests/expected_crashes_3.txt @@ -1,8 +1,5 @@ ********* Start testing of tst_Crashes ********* Config: Using QtTest library @INSERT_QT_VERSION_HERE@, Qt @INSERT_QT_VERSION_HERE@ PASS : tst_Crashes::initTestCase() -QFATAL : tst_Crashes::crash() Received signal 11 - Function time: ms Total time: ms -FAIL! : tst_Crashes::crash() Received a fatal error. -Totals: 1 passed, 1 failed, 0 skipped, 0 blacklisted -********* Finished testing of tst_Crashes ********* +Received signal 11 (SIGSEGV), code 1, for address 0x0000000000000004 + Function time: ms, total time: ms