产生segment fault的原因及调试方法总结

段错误(以下定义摘自C专家编程)

段错误通常是由于解除引用一个未初始化或非法值的指针引起的。以发生频率为序,最终可能导致段错误的常见编程错误是:

1坏指针错误:在指针赋值之前就用它来引用内存;或者向库函数传递一个坏指针(如果调试器显示系统程序中出现了段错误,很可能并不是系统程序引起的段错误,问题可能就出现在自己的代码中);或者指针被释放后还继续访问它的内容。

2改写错误:越过数组边界写入数据,在动态分配的内存空间以外写入数据,或改写一些堆管理数据结构(在动态分配的内存之前的区域写入数据就很容易发生这种情况)

3指针释放引起的错误:释放同一块内存两次,或释放一块未曾使用malloc分类的内存,或释放一个无效的指针。一个极为常见的与释放内存有关的错误就是在 for(p=start;p;p=p->next) 这样的循环中迭代一个链表,并在循环体内使用 free(p) 这样的语句。这样,在下一次循环迭代时,程序就会对已经释放的指针进行解除引用操作,从而导致不可预料的结果。 


问: 以下这段C++代码会有问题吗?有几个printf能正常输出呢?

#include <stdio.h>
#include <stdlib.h>


class Data {
  public :
    void test_data() {
      printf("test_dtata\n");  // printf2
      printf("test_dtata:%d\n", data_); //printf3
    }
  private :
    int data_;
};


class Container {
  public :
    void test_container() {
      printf("test_container\n");  // printf1
      data_.test_data();
    }
  private :
    Data data_;
};


int main()
{
  Container *c = NULL;
  c->test_container();
  return 0;
}

答案是有两个可以输出,第三个会引起segment fault!

test_container
test_dtata
段错误


问: 为什么第一第二个printf能输出,第三个不行?

因为其实  c->test_container();最终等价于 test_container(NULL);然后调用test_data(NULL) ,结果在

  printf("test_dtata:%d\n", data_); //printf3  访问NULL->data_,显然这是非法访问,所以出错。


问:为什么我要举这个例子?

因为printf能输出,直觉就是指针不可能是空的,否则调用不了函数。

我在调试的时候遇到segment fault,具体的项目比这个小例子复杂的多,

一开始是以为线程同步没处理好多次释放了内存导致segment fault,最后发现是未赋值,仅初始化为NULL)。


如何调试segment fault:

1、 gdb 直接调试,用bt来看segment fault的栈情况

2、 对已产生 core dump的,用gdb program.exe core调试,同样用bt来看,默认不产生coredump,如何开启见:http://blog.csdn.net/huangkq1989/article/details/7032776

3、 通过dmesg来看:【引用于: http://zengji.li.blog.163.com/blog/static/87078186201011154156409/】

 kernel : *** : segfault at 0000000000000011 rip 00000032f8670454 rsp 00
0000004128fd30 error 4

这种信息一般都是由内存访问越界造成的,不管是用户态程序还是内核态程序访问越界都会出core, 并在系统日志里面输出一条这样的信息。这条信息的前面分别是访问越界的程序名,进程ID号,访问越界的地址以及当时进程堆栈地址等信息,比较有用的信息是 最后的error number. 在上面的信息中,error number4 ,下面详细介绍一下error number的信息:
在上面的例子中,error number6, 转成二进制就是110, bit2=1, bit1=1, bit0=0, 按照上面的解释,我们可以得出这条信息是由于用户态程序读操作访问越界造成的。
error number是由三个字位组成的,从高到底分别为bit2 bit1bit0,所以它的取值范围是0~7.

bit2: 值为1表示是用户态程序内存访问越界,值为0表示是内核态程序内存访问越界
bit1: 值为1表示是写操作导致内存访问越界,值为0表示是读操作导致内存访问越界
bit0: 值为1表示没有足够的权限访问非法地址的内容,值为0表示访问的非法地址根本没有对应的页面,也就是无效地址


然后用addr2line -e testseg 0000000000400470 -f可得到出问题的函数及对应的行。





  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值