diff --git a/src/testlib/qtestcrashhandler_p.h b/src/testlib/qtestcrashhandler_p.h index d11ea964b58..16209eaae36 100644 --- a/src/testlib/qtestcrashhandler_p.h +++ b/src/testlib/qtestcrashhandler_p.h @@ -28,49 +28,9 @@ #include #endif -#ifdef Q_OS_WIN -#include -#endif - QT_BEGIN_NAMESPACE namespace QTest { namespace CrashHandler { -#if defined(Q_OS_UNIX) && (!defined(Q_OS_WASM) || QT_CONFIG(thread)) - struct iovec IoVec(struct iovec vec); - struct iovec IoVec(const char *str); - - template static ssize_t writeToStderr(Args &&... args) - { - struct iovec vec[] = { IoVec(std::forward(args))... }; - return ::writev(STDERR_FILENO, vec, std::size(vec)); - } - - // async-signal-safe conversion from int to string - struct AsyncSafeIntBuffer - { - // digits10 + 1 for all possible digits - // +1 for the sign - // +1 for the terminating null - static constexpr int Digits10 = std::numeric_limits::digits10 + 3; - std::array array; - constexpr AsyncSafeIntBuffer() : array{} {} // initializes array - AsyncSafeIntBuffer(Qt::Initialization) {} // leaves array uninitialized - }; - - struct iovec asyncSafeToString(int n, AsyncSafeIntBuffer &&result = Qt::Uninitialized); -#elif defined(Q_OS_WIN) - // Windows doesn't need to be async-safe - template static void writeToStderr(Args &&... args) - { - (std::cerr << ... << args); - } - - inline std::string asyncSafeToString(int n) - { - return std::to_string(n); - } -#endif // defined(Q_OS_UNIX) && (!defined(Q_OS_WASM) || QT_CONFIG(thread)) - bool alreadyDebugging(); void blockUnixSignals(); @@ -149,32 +109,6 @@ namespace CrashHandler { int setupAlternateStack(); void freeAlternateStack(); - 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 */); [[maybe_unused]] static void regularHandler(int signum) 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 static ssize_t writeToStderr(Args &&... args) { - return vec; -} -struct iovec IoVec(const char *str) -{ - struct iovec r = {}; - r.iov_base = const_cast(str); - r.iov_len = strlen(str); - return r; + auto makeIovec = [](auto &&arg) { + if constexpr (std::is_same_v, iovec>) { + return arg; + } else { + struct iovec r = {}; + r.iov_base = const_cast(arg); + r.iov_len = strlen(arg); + return r; + } + }; + struct iovec vec[] = { makeIovec(std::forward(args))... }; + return ::writev(STDERR_FILENO, vec, std::size(vec)); } -struct iovec asyncSafeToString(int n, AsyncSafeIntBuffer &&result) +namespace { +// async-signal-safe conversion from int to string +struct AsyncSafeIntBuffer +{ + // digits10 + 1 for all possible digits + // +1 for the sign + // +1 for the terminating null + static constexpr int Digits10 = std::numeric_limits::digits10 + 3; + std::array array; + constexpr AsyncSafeIntBuffer() : array{} {} // initializes array + AsyncSafeIntBuffer(Qt::Initialization) {} // leaves array uninitialized +}; + +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 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)); +} +[[maybe_unused]] 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))); +} +[[maybe_unused]] static void printCrashingSignalInfo(...) {} + bool FatalSignalHandler::pauseOnCrash = false; FatalSignalHandler::FatalSignalHandler() diff --git a/src/testlib/qtestcrashhandler_win.cpp b/src/testlib/qtestcrashhandler_win.cpp index f814a6bc68e..6a9f610eabd 100644 --- a/src/testlib/qtestcrashhandler_win.cpp +++ b/src/testlib/qtestcrashhandler_win.cpp @@ -51,9 +51,11 @@ void printTestRunTime() const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime()); const int msecsTotalTime = qRound(QTestLog::msecsTotalTime()); const char *const name = QTest::currentTestFunction(); - writeToStderr("\n ", name ? name : "[Non-test]", - " function time: ", asyncSafeToString(msecsFunctionTime), - "ms, total time: ", asyncSafeToString(msecsTotalTime), "ms\n"); + + // Windows doesn't have the concept of async-safety, so fprintf() is + // probably as good as WriteFile() and WriteConsole(). + fprintf(stderr, "\n %s function time: %dms, total time: %dms\n", + name ? name : "[Non-test]", msecsFunctionTime, msecsTotalTime); } void generateStackTrace()