Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qtestcrashhandler_p.h
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4//
5// W A R N I N G
6// -------------
7//
8// This file is not part of the Qt API. It exists purely as an
9// implementation detail. This header file may change from version to
10// version without notice, or even be removed.
11//
12// We mean it.
13//
14
15#ifndef QTESTCRASHHANDLER_H
16#define QTESTCRASHHANDLER_H
17
18#include <QtTest/qttestglobal.h>
19
20#include <QtCore/private/qtools_p.h>
21
22#ifdef Q_OS_UNIX
23#include <signal.h>
24#include <sys/mman.h>
25#include <sys/uio.h>
26#include <unistd.h>
27#endif
28
29#ifdef Q_OS_WIN
30#include <iostream>
31# if !defined(Q_CC_MINGW) || (defined(Q_CC_MINGW) && defined(__MINGW64_VERSION_MAJOR))
32# include <crtdbg.h>
33# endif
34#include <qt_windows.h> // for Sleep
35#endif
36
38namespace QTest {
39namespace CrashHandler {
40#if defined(Q_OS_UNIX) && (!defined(Q_OS_WASM) || QT_CONFIG(thread))
41 struct iovec IoVec(struct iovec vec);
42 struct iovec IoVec(const char *str);
43
44 template <typename... Args> static ssize_t writeToStderr(Args &&... args)
45 {
46 struct iovec vec[] = { IoVec(std::forward<Args>(args))... };
47 return ::writev(STDERR_FILENO, vec, std::size(vec));
48 }
49
50 // async-signal-safe conversion from int to string
51 struct AsyncSafeIntBuffer
52 {
53 // digits10 + 1 for all possible digits
54 // +1 for the sign
55 // +1 for the terminating null
56 static constexpr int Digits10 = std::numeric_limits<int>::digits10 + 3;
57 std::array<char, Digits10> array;
58 constexpr AsyncSafeIntBuffer() : array{} {} // initializes array
59 AsyncSafeIntBuffer(Qt::Initialization) {} // leaves array uninitialized
60 };
61
62 struct iovec asyncSafeToString(int n, AsyncSafeIntBuffer &&result = Qt::Uninitialized);
63#elif defined(Q_OS_WIN)
64 // Windows doesn't need to be async-safe
65 template <typename... Args> static void writeToStderr(Args &&... args)
66 {
67 (std::cerr << ... << args);
68 }
69
70 inline std::string asyncSafeToString(int n)
71 {
72 return std::to_string(n);
73 }
74#endif // defined(Q_OS_UNIX) && (!defined(Q_OS_WASM) || QT_CONFIG(thread))
75
76 bool alreadyDebugging();
77 void blockUnixSignals();
78
79#if !defined(Q_OS_WASM) || QT_CONFIG(thread)
80 void printTestRunTime();
81 void generateStackTrace();
82#endif
83
85 Q_TESTLIB_EXPORT void prepareStackTrace();
86
87#if defined(Q_OS_WIN)
88 // Helper class for resolving symbol names by dynamically loading "dbghelp.dll".
89 class DebugSymbolResolver
90 {
91 Q_DISABLE_COPY_MOVE(DebugSymbolResolver)
92 public:
93 struct Symbol
94 {
95 Symbol() : name(nullptr), address(0) {}
96
97 const char *name; // Must be freed by caller.
98 DWORD64 address;
99 };
100
101 explicit DebugSymbolResolver(HANDLE process);
102 ~DebugSymbolResolver() { cleanup(); }
103
104 bool isValid() const { return m_symFromAddr; }
105
106 Symbol resolveSymbol(DWORD64 address) const;
107
108 private:
109 // typedefs from DbgHelp.h/.dll
110 struct DBGHELP_SYMBOL_INFO { // SYMBOL_INFO
111 ULONG SizeOfStruct;
112 ULONG TypeIndex; // Type Index of symbol
113 ULONG64 Reserved[2];
114 ULONG Index;
115 ULONG Size;
116 ULONG64 ModBase; // Base Address of module comtaining this symbol
117 ULONG Flags;
118 ULONG64 Value; // Value of symbol, ValuePresent should be 1
119 ULONG64 Address; // Address of symbol including base address of module
120 ULONG Register; // register holding value or pointer to value
121 ULONG Scope; // scope of the symbol
122 ULONG Tag; // pdb classification
123 ULONG NameLen; // Actual length of name
124 ULONG MaxNameLen;
125 CHAR Name[1]; // Name of symbol
126 };
127
128 typedef BOOL (__stdcall *SymInitializeType)(HANDLE, PCSTR, BOOL);
129 typedef BOOL (__stdcall *SymFromAddrType)(HANDLE, DWORD64, PDWORD64, DBGHELP_SYMBOL_INFO *);
130
131 void cleanup();
132
133 const HANDLE m_process;
134 HMODULE m_dbgHelpLib;
135 SymFromAddrType m_symFromAddr;
136 };
137
138 class Q_TESTLIB_EXPORT WindowsFaultHandler
139 {
140 public:
141 WindowsFaultHandler();
142
143 private:
144 static LONG WINAPI windowsFaultHandler(struct _EXCEPTION_POINTERS *exInfo);
145 };
146 using FatalSignalHandler = WindowsFaultHandler;
147#elif defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
148 class Q_TESTLIB_EXPORT FatalSignalHandler
149 {
150 public:
151 # define OUR_SIGNALS(F) \
152 F(HUP) \
153 F(INT) \
154 F(QUIT) \
155 F(ABRT) \
156 F(ILL) \
157 F(BUS) \
158 F(FPE) \
159 F(SEGV) \
160 F(PIPE) \
161 F(TERM) \
162
163 # define CASE_LABEL(S) case SIG ## S: return QT_STRINGIFY(S);
164 # define ENUMERATE_SIGNALS(S) SIG ## S,
165 static const char *signalName(int signum) noexcept
166 {
167 switch (signum) {
168 OUR_SIGNALS(CASE_LABEL)
169 }
170
171 # if defined(__GLIBC_MINOR__) && (__GLIBC_MINOR__ >= 32 || __GLIBC__ > 2)
172 // get the other signal names from glibc 2.32
173 // (accessing the sys_sigabbrev variable causes linker warnings)
174 if (const char *p = sigabbrev_np(signum))
175 return p;
176 # endif
177 return "???";
178 }
179 static constexpr std::array fatalSignals = {
180 OUR_SIGNALS(ENUMERATE_SIGNALS)
181 };
182 # undef CASE_LABEL
183 # undef ENUMERATE_SIGNALS
184
185 static constexpr std::array crashingSignals = {
186 // Crash signals are special, because if we return from the handler
187 // without adjusting the machine state, the same instruction that
188 // originally caused the crash will get re-executed and will thus cause
189 // the same crash again. This is useful if our parent process logs the
190 // exit result or if core dumps are enabled: the core file will point
191 // to the actual instruction that crashed.
192 SIGILL, SIGBUS, SIGFPE, SIGSEGV
193 };
194 using OldActionsArray = std::array<struct sigaction, fatalSignals.size()>;
195
196 FatalSignalHandler();
197 ~FatalSignalHandler();
198
199 private:
200 Q_DISABLE_COPY_MOVE(FatalSignalHandler)
201
202 static OldActionsArray &oldActions();
203 auto alternateStackSize();
204 int setupAlternateStack();
205 void freeAlternateStack();
206
207 template <typename T> static
208 std::enable_if_t<sizeof(std::declval<T>().si_pid) + sizeof(std::declval<T>().si_uid) >= 1>
209 printSentSignalInfo(T *info)
210 {
211 writeToStderr(" sent by PID ", asyncSafeToString(info->si_pid),
212 " UID ", asyncSafeToString(info->si_uid));
213 }
214 static void printSentSignalInfo(...) {}
215
216 template <typename T> static
217 std::enable_if_t<sizeof(std::declval<T>().si_addr) >= 1> printCrashingSignalInfo(T *info)
218 {
219 using HexString = std::array<char, sizeof(quintptr) * 2>;
220 auto toHexString = [](quintptr u, HexString &&r = {}) {
221 int shift = sizeof(quintptr) * 8 - 4;
222 for (size_t i = 0; i < sizeof(quintptr) * 2; ++i, shift -= 4)
224 struct iovec vec;
225 vec.iov_base = r.data();
226 vec.iov_len = r.size();
227 return vec;
228 };
229 writeToStderr(", code ", asyncSafeToString(info->si_code),
230 ", for address 0x", toHexString(quintptr(info->si_addr)));
231 }
232 static void printCrashingSignalInfo(...) {}
233 static void actionHandler(int signum, siginfo_t *info, void * /* ucontext */);
234
235 [[maybe_unused]] static void regularHandler(int signum)
236 {
237 actionHandler(signum, nullptr, nullptr);
238 }
239
240 void *alternateStackBase = MAP_FAILED;
241 static bool pauseOnCrash;
242 };
243#else // Q_OS_WASM or weird systems
244class Q_TESTLIB_EXPORT FatalSignalHandler {};
245inline void blockUnixSignals() {}
246#endif // Q_OS_* choice
247} // namespace CrashHandler
248} // namespace QTest
250
251#endif // QTESTCRASHHANDLER_H
QString str
[2]
std::list< QString >::iterator Name
Definition lalr.h:28
Combined button and popup list for selecting options.
constexpr char toHexLower(char32_t value) noexcept
Definition qtools_p.h:32
void * HANDLE
constexpr Initialization Uninitialized
Initialization
static QT_WARNING_DISABLE_FLOAT_COMPARE ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qreal threshold)
Definition qbezier.cpp:207
quint32 Tag
Flags
#define Size(name)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint name
GLfloat n
GLenum array
GLuint GLuint64EXT address
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define MAP_FAILED
size_t quintptr
Definition qtypes.h:167
HINSTANCE HMODULE
QObject::connect nullptr
QHostInfo info
[0]
QJSValueList args