zoukankan      html  css  js  c++  java
  • 程序崩溃时的堆栈捕捉

    前述:

    工作中,发现项目里的进程崩溃时,不会生成core文件,排查顺序:1、查看core文件的生成路径:cat /proc/sys/kernel/core_pattern; 2、查看core信息设置的是否正确:ulimit -a。

    经过排查后,我发现我本地的环境没有问题,还写过demo测试,能生成core的。

    core的一些设置,参考:https://blog.csdn.net/lanmolei814/article/details/45201693

    本篇主要解决了两个问题:1、为什么没有core文件生成;2、为什么栈溢出的时候没有堆栈日志。

    发现问题1:

    1、我发现项目的代码有添加信号捕捉的功能(可以参考下面的代码CrashHandler);

    2、每次捕捉后,确实有堆栈日志输出的,这个功能是正常的;

    3、那么问题出在哪里呢?

    答:我在调试的时候,发现每次在打印完堆栈日志,程序就安全的退出了,不会有core文件生成,当时就怀疑是exit(-1)导致的,所以自己肯定会测试下exit(signo),但这会导致可怕的事故发生,那就是程序死循环了,一直打印堆栈日志,不会正常退出。当然,在没有core文件的情况下,如果定位bug,我也研究了的。(因为还有堆栈日志可以使用,所以直接能看到崩溃的函数调用栈,但难受的是:生成环境是release 不加 -g的版本,也就是没有符号文件;所以我得利用nm找到函数地址,然后再gdb反汇编那个函数地址,通过偏移定位到引起崩溃的那行代码)

    4、解决方案:使用代码注释的方法2。

    分析:

    crash_signal.cpp 代码:

    #include<iostream>
    #include<stdlib.h>
    #include <signal.h>       /* for signal */
    #include <execinfo.h>     /* for backtrace() */
    using namespace std;
    void CrashHandler(int signo) {
        cout << "crash sig:" << signo;
    
        int size = 16;
        void * array[16];
        int stack_num = backtrace(array, size);
        char ** stacktrace = backtrace_symbols(array, stack_num);
        for (int i = 0; i < stack_num; ++i)
        {
            cout << stacktrace[i] << endl;
        }
    
        free(stacktrace);
    
        exit(-1);//方法1:程序就直接退出了,不会有生成core文件生成
    
        //signal(signo, SIG_DFL);//方法2: /* 恢复信号默认处理 */
        //raise(signo);                   /* 重新发送信号 */
    }
    
    int fun(int n)
    {
        if (n <= 0)
            return 0;
    {//测试1
        int a = 0;
        n = n / a;//目的:测试信号SIGFPE
      return 0;
    } {//测试2 int nLen = 10240; char arr[10240] = { 0 }; arr[0] = 0x0; arr[1] = 0x0; arr[2] = 0x1; arr[3] = 0x1; return 1 + fun(n - 1) + *(arr + 3);//这会造成栈溢出,ulimit -s可以查看系统的栈大小,当然也可以手动设置
    }
    } int fun_stack_overflow() { int nTotal = fun(1024); return nTotal; } int main() { signal(SIGABRT, CrashHandler); signal(SIGFPE, CrashHandler); signal(SIGILL, CrashHandler); signal(SIGSEGV, CrashHandler); int nSum = fun_stack_overflow(); cout << nSum << endl; return 0; }

    编译:g++ -g crash_signal.cpp -o crash.out

    测试1:(当前使用的是测试1代码噢)

    1)、测试方法1:gdb crash.out打开,break CrashHandler下一个断点,run运行程序。

     测试结果:有堆栈日志,但程序退出时,没有core文件生成。注:图中第一次中断是gdb捕捉的,第二次是程序里的捕捉。

    2)、改善为方法2,退出程序。

     测试结果:有core文件生成,有堆栈日志输出。注:图中第一次中断时gdb捕捉的,第二次是程序的中断,第三次是raise返回给程序的。

    测试2:(使用的测试2代码,方法1和2不限)

     1)测试结果,有core文件,但是没有堆栈日志。注:第一次中断是gdb捕捉的,第二次应该是gdb返回给程序的?

    分析测试2:测试的崩溃原因是堆栈溢出了,即就是递归导致栈满了。但为何程序的signal信号没有捕捉到堆栈满的错误呢,gdb返回的是段错误呀,我猜测:低版本的gdb可能也无法回溯出堆栈信息吧,这个还得继续研究。

    以上就是本次的研究成果,把方法2应用到项目里试试吧。

    转载请注明出处!

  • 相关阅读:
    C#图片无损压缩
    as3.0 动态文本属性大全
    卡​马​克​卷​轴​算​法​研​究​_​地​图​双​缓​冲
    春卷活动心得
    移动端videojs视频插件使用直播流rtmp、hls、http-flv的注意事项
    在Windows2008系统中利用IIS建立FTP服务器
    winform 窗体自适应 根据新窗体大小按比例放缩
    HTTPS抓包
    数据库 事物 锁
    sql 事物 锁 快照(转发的,写的非常好)
  • 原文地址:https://www.cnblogs.com/mingbujian/p/12676217.html
Copyright © 2011-2022 走看看