Summary
The POSIX signal handlers in src/platform/posixsignalnotifier.cpp call functions that are not async-signal-safe, which can cause deadlocks, corruption, or secondary crashes during crash handling.
Details
Crash handler (lines 85-96)
action.sa_handler = [](int sig) {
constexpr struct sigaction default_action = {};
::sigaction(sig, &default_action, nullptr); // OK: async-signal-safe
qCritical("Crash signal %d received", sig); // NOT async-signal-safe
Stacktrace::process([](const Stacktrace::Frame& frame) {
qCritical() << frame; // NOT async-signal-safe
});
};
qCritical() uses Qt's logging infrastructure (locks, allocations, I/O). Stacktrace::process() calls dladdr(), backtrace(), and abi::__cxa_demangle() -- all of which allocate memory. If the crash occurred while malloc's lock was held, these calls deadlock.
Unwatch handler (lines 153-162)
action.sa_handler = [](int sig) {
qWarning("Signal %d received twice; terminating ungracefully", sig); // NOT safe
::exit(EXIT_FAILURE); // NOT safe! Runs atexit handlers, flushes buffers
};
::exit() runs atexit handlers and flushes stdio, which can deadlock in signal context. Must use _exit().
Suggested Fix
// Crash handler - use only async-signal-safe functions
action.sa_handler = [](int sig) {
constexpr struct sigaction default_action = {};
::sigaction(sig, &default_action, nullptr);
// write() is async-signal-safe
const char msg[] = "Fatal signal received\n";
(void)::write(STDERR_FILENO, msg, sizeof(msg) - 1);
// Re-raise to get core dump with default handler
::raise(sig);
};
// Unwatch handler
action.sa_handler = [](int sig) {
const char msg[] = "Signal received twice; terminating\n";
(void)::write(STDERR_FILENO, msg, sizeof(msg) - 1);
_exit(EXIT_FAILURE); // _exit, NOT exit
};
For stack traces, consider sigaltstack + fork() to collect in a child process, or accept that crash-time stack traces are best-effort.
Impact
Signal handlers can deadlock or crash during crash handling, preventing useful diagnostics and potentially leaving the application in an unresponsive state instead of terminating cleanly.
Summary
The POSIX signal handlers in
src/platform/posixsignalnotifier.cppcall functions that are not async-signal-safe, which can cause deadlocks, corruption, or secondary crashes during crash handling.Details
Crash handler (lines 85-96)
qCritical()uses Qt's logging infrastructure (locks, allocations, I/O).Stacktrace::process()callsdladdr(),backtrace(), andabi::__cxa_demangle()-- all of which allocate memory. If the crash occurred while malloc's lock was held, these calls deadlock.Unwatch handler (lines 153-162)
::exit()runs atexit handlers and flushes stdio, which can deadlock in signal context. Must use_exit().Suggested Fix
For stack traces, consider
sigaltstack+fork()to collect in a child process, or accept that crash-time stack traces are best-effort.Impact
Signal handlers can deadlock or crash during crash handling, preventing useful diagnostics and potentially leaving the application in an unresponsive state instead of terminating cleanly.