I want to make a crash/exception handler for my Qt application. I have the handler working already (not included in the code below). The problem is on Windows that it only works if the crash occures in the same thread where signal()
and std::set_terminate()
is called.
On Linux it seems to work for all threads by default.
Is there a way to make it work for all application threads on Windows?
#include "mainwindow.h"
#include <QApplication>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <exception>
void seg_handler(int sig)
{
// Crash/exception handling code
// ...
exit(1);
}
void std_handler( void ) {
seg_handler(1);
}
int main(int argc, char *argv[]) {
signal(SIGSEGV, seg_handler);
std::set_terminate( std_handler );
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
After very much research combined with my lack of knowledge on the Windows OS I finally reached a working solution that automatically sets up terminate functions for new threads.
The trick is to create a dll to handle your crashes/exceptions. In your dll implement the reserved DllMain()
function. This function receives notifications every time a new thread or process is attached to the main process. The fdwReason
parameter holds information about the event.
DLL_THREAD_ATTACH
DLL_PROCESS_ATTACH
Implement your termination handlers in the dll and call signal()
and std::set_terminate()
for each thread or process that is started.
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved) {
if (fdwReason==DLL_THREAD_ATTACH) {
signal(SIGSEGV, seg_handler);
std::set_terminate( std_handler );
}
if (fdwReason==DLL_PROCESS_ATTACH) {
signal(SIGSEGV, seg_handler);
std::set_terminate( std_handler );
}
return TRUE;
}
My handlers look like this:
#include <windows.h>
#include "StackWalker.h"
#include <signal.h>
#include <DbgHelp.h>
#include <iostream>
#include <qdebug.h>
void seg_handler(int sig) {
// Simple callstack
unsigned int i;
void * stack[ 100 ];
unsigned short frames;
SYMBOL_INFO * symbol;
HANDLE process;
process = GetCurrentProcess();
SymInitialize( process, NULL, TRUE );
frames = CaptureStackBackTrace( 0, 100, stack, NULL );
symbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 );
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof( SYMBOL_INFO );
for( i = 0; i < frames; i++ ) {
SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol );
printf( "%i: %s - 0x%0X\n", frames - i - 1, symbol->Name, symbol->Address );
}
free( symbol );
// Detailed callstack/crashinfo
StackWalker sw;
sw.ShowCallstack(GetCurrentThread());
exit(1);
}
void std_handler( void ) {
seg_handler(1);
}
The handlers above use StackWalker
Edit:
Of course you need to add the termination handlers to your main thread as well:
int main(int argc, char *argv[]) {
CALL_LOGGER();
signal(SIGSEGV, seg_handler);
std::set_terminate( std_handler );
return runapp(argc, argv);
}
Hope this helps someone
-Jakob
I suspect that SetUnhandledExceptionFilter
is a better way of trapping crashes on Windows than signal
. It's set globally (so you don't need the DLL to install a handler in each thread) and doesn't discard information about the fault (it's possible there's some way of recovering the true cause of the SIGSEGV
but I don't immediately know how).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With