Segmentation Fault错误原因及调试方法
目录

非法地址访问将导致Segmentation Fault错误,并使OS发送SIGSEGV信号给进程,并强制停止进程。 非法地址访问包括:

  1. NULL指针访问(地址0);
  2. 栈中地址内容被破坏等原因导致的非法地址访问;
  3. 栈溢出导致访问超出了已分配的地址空间,比如递归调用;

栈中地址内容被破坏

栈中地址内容被破坏,比如上层FP地址、Code返回地址等,很可能导致Segmentation Fault。 改变程序运行地址的方法有:

  1. 代码中条件判断语句,如if, for, switch:这种情况下地址是硬写入到可执行文件img中,并加载到运行时的只读代码段,尝试修改就会直接产生Segmentation Fault
  2. GOT/PLT调用函数:
  3. 函数返回,执行ret指令:如数组缓冲区溢出栈中导致上层函数返回地址被改写;

gdb分析core时,常常先bt打印出函数调用栈。 但是在某些情况下进程的栈内容被破坏,这就会导致bt输出的内容错误(如函数符号名不显示)。 可以结合寄存器RSP、RIP的内容分析栈是否被破坏。 在得到破坏的内容和内容地址后,可以再使用gdb watch方法设置监视点,查找被改写时执行的代码。

栈溢出后使用信号处理函数备用栈

Linux可以注册signal handler,以便在收到信号后退出前进行一些操作。 但是如果栈溢出,则说明栈已经满了,因此也无法进一步压入signal handler函数去执行。 为了解决此问题,需要在堆中申请一块区域作为备用栈,并通过sigaltstack函数注册备用栈, 以便signal handler使用。

附内存检查工具:

  • 运行时设置MALLOC_CHECK_
  • glibc-utils中的mtrace, memusage
  • Leaktracer, Valgrind, ElectricFence

参考:

  • Debug Hacks
/ty阳光/ty 于 2014-09-16 21:26 时评论:
第一次看到sigaltstack,受益匪浅

发表评论