Segmentation fault段错误调试总结

Segmetation fault也叫做段错误,引发的原因有好多,这里我们只说一下段错误发生时的调试方法。

方法1:加打印printf。这是最基本的往往也很有效的方法,在哪里Core掉就会在哪里停止打印--一目了然。同时这种方法也存在一个致命缺陷:如果恰巧Core掉的地方没加打印而程序代码又非常庞大又可能是多线程的,那查找问题等同于大海捞针。

方法2:gdb调试。加gdb调试往往能在Core dump时抓到,甚至能抓到哪一个文件哪个类哪个函数哪一行,甚是精确。要确保GDB能抓到可用信息要做一些准备:

   (1) 加-g 参数,这样才会有调试信息。 我想是个程序员就应该知道吧。

    (2) 在Makefile 中加上 -fstack-protector 和 -fstack-protector-all 信息,确保函数调用栈不丢失,当然只能是一定程度的不丢失,要完成保留住是不太可能的,但起码可以得到栈顶函数。

有了上面两点对大多数的Segmentation fault都能抓住,但是函数调用栈彻底乱掉或者在动态库so中Core而这个库编译时没有加-g参数,这些情况就gdb就无能为力了。

方法3:手动获取函数调用栈。这种方法其实是借住两个系统函数backtrace和backtrace_symbol来获取函数调用栈的,把这两个函数放在信号处理函数中:当收到 SIGSEG时在信号处理函数中调用这两个函数打印函数调用栈,在没用GDB调试的时候这种方法可以代替gdb的一部分功能,这听起来是不是非常酷啊,来看一看实现吧:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

static void SignalHandle(int sig)
{
    void *array[20];
    size_t size;
    char **strings;
    int i;
    size = backtrace(array, 10);
    strings = backtrace_symbols(array, size);
    printf("SIGNAL ocurre %d, stack tarce:\n", sig);
    printf("obtained %d stack frames.\n", size);

    for (i = 0; i < size; i++)
        printf("%s\n", strings);

    free(strings);
    printf("stack trace over!\n");
    exit(0);
}

int main(int argc, char **argv)
{
    signal(SIGSEGV, SignalHandle);
    //...程序主体
}

当然这种方法在没有GDB时候会大显身手,经过实验就是有gdb的时候这种方法有时比gdb抓到调用栈要多一层;当然这种方法和用gdb调试一样要加-g和栈保护参数-fstack-protector 和 -fstack-protector-all。其缺点就是抓到的调用栈无效,这是什么意思呢?有时发生core dump,能定位到甚至哪一行,但是那一行根本没有明显的错误;或者追到没有调试信息的动态库里如glibc。当然这些情况大多数调试方法都无能为力,只能依靠程序员的经验了。

方法4:经验之谈(一)。如果我们的程序是多线程的,发生core dump用以上方法均无效,除了仔细排查代码外,还有这么一方法让我们缩小范围。

在每个线程中获取线程id(在我的博文《多线程调试的一点思路》中介绍),在出错时在gdb下查看当前线程info thread。这样知道是哪一个线程引起的core dump,将大大缩小查找范围。

(未完待续中....)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一马途追

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值