如果程序出现Segment fault错误,该如何排错?谈SIGBUS和SIGSEGV
2011-11-04 12:27
411 查看
2010年网易有道的一道考基础知识的面试题,如果程序出现Segment fault错误,该如何排错?那么,什么是Segment fault?这里笔者引用一篇文章,说的很清楚。
SIGBUS和SIGSEGV也许是我们在平时遇到的次数最多的两个内存错误信号。内存问题一直是最令我们头疼的事情,弄清楚两个信号的发生缘由对我们很好的理解程序的运行是大有裨益的。
我们来看两段程序:
//testsigsegv.c
int main() {
char *pc = (char*)0x00001111;
*pc = 17;
}
//testsigbus.c
int main() {
int *pi = (int*)0x00001111;
*pi = 17;
}
上面的代码那么的相似,我们也同样用gcc编译(加上-g选项,便于gdb调试;平台Solaris Sparc),执行结果也都是dump core。但通过GDB对core进行观察,你会发现细微的不同。第一个例子出的core原因是:Program terminated with signal 11, Segmentation fault. 而第二个例子的core则提示:Program terminated with signal 10, Bus error. 两者有什么不同呢?这两段代码的共同点都是将一个非法地址赋值给指针变量,然后试图写数据到这个地址。
如果要说清楚这个问题,我们就要结合汇编码和一些计算机的体系结构的知识来共同分析了。
先来看testsigsegv.c的汇编码:
... ...
main:
!#PROLOGUE# 0
save %sp, -120, %sp
!#PROLOGUE# 1
sethi %hi(4096), %i0
or %i0, 273, %i0
st %i0, [%fp-20]
ld [%fp-20], %i1
mov 17, %i0
stb %i0, [%i1]
nop
ret
restore
... ...
我们关注的是这句:stb %i0, [%i1]
从计算机底层的执行角度来说,过程是如何的呢?%i0寄存器里存储的是立即数17,我们要将之存储到寄存器%i1的值指向的内存地址。这一过程对于CPU来说其指挥执行的正常过程是:将寄存器%i0中的值送上数据总线,将寄存器%i1的值送到地址总线,然后使能控制总线上的写信号完成这一向内存写1 byte数据的过程。
我们再看testsigbus.c的汇编码:
... ...
main:
!#PROLOGUE# 0
save %sp, -120, %sp
!#PROLOGUE# 1
sethi %hi(4096), %i0
or %i0, 273, %i0
st %i0, [%fp-20]
ld [%fp-20], %i1
mov 17, %i0
st %i0, [%i1]
nop
ret
restore
... ...
同样最后一句:st %i0, [%i1],CPU执行的过程与testsigsegv.c中的一致(只是要存储数据长度是4字节),那为什么产生错误的原因不同呢?一个是SIGSEGV,而另一个是SIGBUS。这里涉及到的就是对内存地址的校验的问题了,包括对内存地址是否对齐的校验以及该内存地址是否合法的校验。
我们假设如果首先进行的内存地址是否合法的校验(是否归属于用户进程的地址空间),那么我们回顾一下,这两个程序中的地址0x00001111显然都不合法,按照这种流程,两个程序都应该是SIGSEGV导致的core才对,但是事实并非如此。那难道是先校验内存地址的对齐?我们再看这种思路是否合理?
testsigsegv.c中,0x00001111这个地址值被赋给了char *pc;也就是告诉CPU通过这个地址我们要存取一个字节的值,对于一个字节长度的数据,无所谓对齐,所以该地址通过对齐校验;并被放到地址总线上了。而在testsigbus.c里,0x00001111这个地址值被赋给了int *pi;也就是告诉CPU通过这个地址我们要存取一个起码4个字节的值,那么对于长度4个字节的对象,其存放地址起码要被4整除才可以,而0x00001111这个值显然不能满足要求,也就不能通过内存对齐的校验。也就是说SIGBUS这个信号在地址被放到地址总线之后被检查出来的不符合对齐的错误;而SIGSEGV则是在地址已经放到地址总线上后,由后续流程中的某个设施检查出来的内存违法访问错误。
一般我们平时遇到SIGBUS时总是因为地址未对齐导致的,而SIGSEGV则是由于内存地址不合法造成的。
原文地址:http://bigwhite.blogbus.com/logs/12296535.html
相关文章推荐
- 如果程序出现Segment fault错误,该如何排错?谈SIGBUS和SIGSEGV
- 在Linux系统下,如果程序中出现segment fault,如何可以让系统产生core dump文件?如何用gdb来跟踪出错的地方?
- [转]python执行bash指令,如果指令返回错误,如何优雅的结束python程序
- 如何解决sql server 2000安装过程中出现 安装程序配置服务器失败 错误
- maven spring restful 以json返回时,如果出现406错误该如何处理
- 如果浏览器报JavaScript出现错误导致代码程序中断,可以这样解决!
- 安装SQL Server 2000时出现以下错误提示:“以前的某个程序安装已在安装计算机创建挂起的文件操作,运行安装程序之前必须重新启动计算机” 说明:如果重启计算机无法解决问题,可能有以下两个原因
- DB2在导入数据时,如果数据量过大,出现事务日志满的错误(Database transaction log is full)该如何解决,commitcount使用
- 程序出现错误如何解决
- 调试时出现:“没有找到 MSVCR80D.dll,因此这个程序未能启动,重新安装应用程序,可能会修复此问题”错误提示,如何解决?
- 如果遇到Hadoop集群正常,MapReduce作业运行出现错误,如何来查看作业运行日志(图文详解)
- 如果你的Android Studio点击运行出现如下所示错误如何解决
- windows2008下配置iis时出现错误“由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射。”
- Image组件加载图片出现错误后如何让程序继续正常的运行?
- 导入项目工程后如果出现下面的错误该如何解决
- 如果一个程序同时链接了MSVCRT.lib和libcmt.lib回出现函数重定义错误
- 在安装office2003时,出现"安装程序包的语言不受系统支持"的错误,如何解决?
- 如果BarTender出现卸载不干净的问题如何处理
- 如何利用 JConsole观察分析Java程序的运行,进行排错调优
- linux socket编程中出现发送或接收错误时退出程序问题