call stack when Segmentation fault

123 views Asked by At

I code this(backtrace.hpp) to show the call stack when my program crashed like segmentation fault.

#pragma once
#include <map>
#include <iostream>
#include <signal.h>
#include <sys/stat.h>
#include <execinfo.h>
#include <sys/types.h>
#include <unistd.h>

static const std::map<int, std::string> signals_map =
{
    {SIGSEGV, "SIGSEGV"},
    {SIGABRT, "SIGABRT"},
    {SIGINT, "SIGINT"},
    {SIGFPE, "SIGFPE"},
    {SIGILL, "SIGILL"},
    {SIGSYS, "SIGSYS"},
    {SIGBUS, "SIGBUS"},
    {SIGIOT, "SIGIOT"},
    {SIGTRAP, "SIGTRAP"},
};

class Backtrace
{
private:
    static void ExceptionHandler(int signum, siginfo_t* info, void* ctx){
        int nptrs;
        void *buffer[1024];
        char **strings;

        nptrs = backtrace(buffer, 1024);
        strings = backtrace_symbols(buffer, nptrs);
        if (strings == NULL) {
            exit(EXIT_FAILURE);
        }

        std::cout<<std::endl<<"****** Crash Backtrace signal: "<<signals_map.at(signum)<<"******"<<std::endl<<std::endl;
        for (int i = 2; i < nptrs; i++) {
            std::cout<<"     "<<strings[i]<<std::endl;
        }

        free(strings);
        signal(signum, SIG_DFL);
    }
public:
    Backtrace(){
        struct sigaction action;
        sigemptyset(&action.sa_mask);
        action.sa_sigaction = &ExceptionHandler;
        action.sa_flags = SA_SIGINFO;
        for (const auto& signals: signals_map)
        {
            if (0 > sigaction(signals.first, &action, NULL))
            {
                std::cout<<"sigaction failed:"<<signals.second<<std::endl;
            }
        }
    }
    ~Backtrace(){}
};

Usually, it is usefull. But sometimes, I just got info like: $ /bin/sh: line 1: 6571 Segmentation fault There is no backtrace output. Why does this happen?

In my code, I use the backtrace.hpp like this:

#inlcude "backtrace.hpp"
int main(){
    Backtrace b;
    ...
}
1

There are 1 answers

0
Employed Russian On

Why does this happen?

There are very few functions you can legally use in a signal handler (the async-signal-safe ones).

The malloc and free are not safe, backtrace_symbols() calls malloc(), and using std::cout is simply asking for trouble.

It's possible to print the crash stack trace fairly reliably, but that requires a lot of care (and quite a lot of code), and you aren't careful at all.

If your crash is happening due to heap corruption (as many crashes are), calling backtrace_symbols() may crash, deadlock or simply fail. If either of these happens, your code would fail to print anything.