summaryrefslogtreecommitdiffstats
path: root/src/testlib/qtestcrashhandler_unix.cpp
diff options
context:
space:
mode:
authorThiago Macieira <[email protected]>2025-05-19 10:20:32 -0700
committerThiago Macieira <[email protected]>2025-05-23 20:36:45 -0700
commit09edc851c52d97bcea6a4d0b4e94c6760439d84b (patch)
treec4b64fd6b8bb994fc67db9bfbcf2cfb6c066f41e /src/testlib/qtestcrashhandler_unix.cpp
parent9a66c7c1b9e1488f54f6ecfaab714fdc2e770a7d (diff)
QTest::CrashHandler: move the Unix async-safe I/O code to the .cpp
This declutters the header from code that doesn't need to be there and is only used in the .cpp anyway. This code used to be in qtestcase.cpp before commit c0014becca2cd376eadd5c8a0265e5cf47c9aa01, which we now amend. Additionally, since Windows code doesn't need to be async-safe anyway, we can simplify it. I'm also going to need the toHexString() lambda in another place. Change-Id: Ic9571bac864dfb31564cfffd785e8ab15cab3ae5 Reviewed-by: Edward Welbourne <[email protected]> Reviewed-by: Ahmad Samir <[email protected]>
Diffstat (limited to 'src/testlib/qtestcrashhandler_unix.cpp')
-rw-r--r--src/testlib/qtestcrashhandler_unix.cpp67
1 files changed, 56 insertions, 11 deletions
diff --git a/src/testlib/qtestcrashhandler_unix.cpp b/src/testlib/qtestcrashhandler_unix.cpp
index f0ffe36dd66..86a77312ba4 100644
--- a/src/testlib/qtestcrashhandler_unix.cpp
+++ b/src/testlib/qtestcrashhandler_unix.cpp
@@ -68,21 +68,36 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-namespace QTest {
-namespace CrashHandler {
-struct iovec IoVec(struct iovec vec)
+template <typename... Args> static ssize_t writeToStderr(Args &&... args)
{
- return vec;
+ auto makeIovec = [](auto &&arg) {
+ if constexpr (std::is_same_v<std::decay_t<decltype(arg)>, iovec>) {
+ return arg;
+ } else {
+ struct iovec r = {};
+ r.iov_base = const_cast<char *>(arg);
+ r.iov_len = strlen(arg);
+ return r;
+ }
+ };
+ struct iovec vec[] = { makeIovec(std::forward<Args>(args))... };
+ return ::writev(STDERR_FILENO, vec, std::size(vec));
}
-struct iovec IoVec(const char *str)
+
+namespace {
+// async-signal-safe conversion from int to string
+struct AsyncSafeIntBuffer
{
- struct iovec r = {};
- r.iov_base = const_cast<char *>(str);
- r.iov_len = strlen(str);
- return r;
-}
+ // digits10 + 1 for all possible digits
+ // +1 for the sign
+ // +1 for the terminating null
+ static constexpr int Digits10 = std::numeric_limits<int>::digits10 + 3;
+ std::array<char, Digits10> array;
+ constexpr AsyncSafeIntBuffer() : array{} {} // initializes array
+ AsyncSafeIntBuffer(Qt::Initialization) {} // leaves array uninitialized
+};
-struct iovec asyncSafeToString(int n, AsyncSafeIntBuffer &&result)
+struct iovec asyncSafeToString(int n, AsyncSafeIntBuffer &&result = Qt::Uninitialized)
{
char *ptr = result.array.data();
if (false) {
@@ -127,7 +142,10 @@ struct iovec asyncSafeToString(int n, AsyncSafeIntBuffer &&result)
r.iov_len = ptr - result.array.data();
return r;
};
+} // unnamed namespace
+namespace QTest {
+namespace CrashHandler {
bool alreadyDebugging()
{
#if defined(Q_OS_LINUX)
@@ -349,6 +367,33 @@ void blockUnixSignals()
pthread_sigmask(SIG_BLOCK, &set, nullptr);
}
+template <typename T> static
+ std::enable_if_t<sizeof(std::declval<T>().si_pid) + sizeof(std::declval<T>().si_uid) >= 1>
+printSentSignalInfo(T *info)
+{
+ writeToStderr(" sent by PID ", asyncSafeToString(info->si_pid),
+ " UID ", asyncSafeToString(info->si_uid));
+}
+[[maybe_unused]] static void printSentSignalInfo(...) {}
+
+template <typename T> static std::enable_if_t<sizeof(std::declval<T>().si_addr) >= 1>
+printCrashingSignalInfo(T *info)
+{
+ using HexString = std::array<char, sizeof(quintptr) * 2>;
+ 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)));
+}
+[[maybe_unused]] static void printCrashingSignalInfo(...) {}
+
bool FatalSignalHandler::pauseOnCrash = false;
FatalSignalHandler::FatalSignalHandler()