Question

I'm implementing a simple crash logger for my C++ application:

static void handler(int, siginfo_t * info, void *) {
    void *array[1000];

    switch (info->si_signo) {
    case SIGILL:
        Logger() << "Received SIGILL";
        break;
    case SIGSEGV:
        Logger() << "Received SIGSEGV";
        break;
    case SIGBUS:
        Logger() << "Received SIGBUS";
        break;
    case SIGSYS:
        Logger() << "Received SIGSYS";
        break;
    default:
        break;
    }

    // get void*'s for all entries on the stack
    const size_t size = backtrace(array, 1000);

    // print out all the frames
    char ** symbols = backtrace_symbols(array, size);
    for(size_t i = 0; i < size; ++i)
    {
        Logger() << symbols[i];
    }

    free(symbols);
    exit(EXIT_FAILURE);
}

struct sigaction SignalAction;
SignalAction.sa_flags = SA_SIGINFO;
SignalAction.sa_sigaction = handler;
sigemptyset(&SignalAction.sa_mask);
sigaction(SIGSEGV, &SignalAction, NULL);
sigaction(SIGBUS, &SignalAction, NULL);
sigaction(SIGILL, &SignalAction, NULL);

I haven't tested it on Linux yet, but on OS X the specific trace item that I'm interested in, the one thatr has caused the signal, is not being printed (entry number 2):

: " Received SIGSEGV" 
: " 0   App                       0x0000000100253d15 _ZL7handleriP9__siginfoPv + 229" 
: " 1   libsystem_platform.dylib  0x00007fff8ff0f5aa _sigtramp + 26" 
: " 2   ???                       0x000000000000000c 0x0 + 12" 
: " 3   App                       0x000000010000dfa7 _ZN11CMainWindow13initShortcutsEv + 231" 
: " 4   App                       0x000000010000d059 _ZN11CMainWindowC2EP7QWidget + 1001" 
: " 5   App                       0x00000001000091d9 main + 6217" 
: " 6   App                       0x00000001000070a5 _start + 227" 
: " 7   App                       0x0000000100006fc1 start + 33" 

Why is this happening, and can I fix this?

P. S. This is a debug build. There was no actual segfault, it was simulated with raise(SIGSEGV). raise was called from a method , that, in turn, was called from MainWindow::initShortcuts.

Was it helpful?

Solution 2

Entry number 2 has very special address. It's 0x000000000000000c and you have to know that there is interrupt description table. According to http://en.wikipedia.org/wiki/Interrupt_Descriptor_Table it may be Stack Fault.

However as Ken pointed, doing what you are doing is bad. It's like trying to remember license plate of car that hit you when you aorta is torn apart. You can do it but what for?

Maybe instead of doing it try learn how to use strace http://en.wikipedia.org/wiki/Strace.

OTHER TIPS

The idea of building a crash logger with a signal handler is fundamentally flawed. From the "NOTE" section of the sigaction man page:

The following functions are either reentrant or not interruptible by signals and are async-signal safe. Therefore applications may invoke them, without restriction, from signal-catching functions:

[… async-signal safe function list omitted …]

All functions not in the above lists are considered to be unsafe with respect to signals. That is to say, the behaviour of such functions when called from a signal handler is undefined. In general though, signal handlers should do little more than set a flag; most other actions are not safe.

None of backtrace(), backtrace_symbols(), free(), or exit() are safe to call within a signal handler. Almost certainly, stuff within your Logger or operator<< is also unsafe.

As to why the signal-provoking function is not in the backtrace, it's evidently cause by how the signal handler context is set up by the kernel. A backtrace is obtained by examining stack frames as constructed by call statements and function prologs. A signal handler is not invoked as a normal function call, so there's no particular reason to expect that the chain of stack frames would be set up properly.

In fact, signal handlers can be made to run on a completely different stack than normal code. See sigaltstack().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top