`
idning
  • 浏览: 138444 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

关于 SIGBUS和SIGSEGV (摘抄)

阅读更多

 

也谈'SIGBUS和SIGSEGV' - [技术前沿]

版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://bigwhite.blogbus.com/logs/12296535.html

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则是由于内存地址不合法造成的。

 

分享到:
评论

相关推荐

    适用于 iOS 的 Airbrake 通知器_Objective-C_代码_下载

    只需在您的项目中添加几行代码和一些额外的文件,您的应用就会在遇到崩溃或异常时自动打电话回家。这些报告直接发送到 Airbrake,您可以在其中查看回溯、设备类型、应用程序版本等信息。 信号 通知程序处理所有未...

    linux信号量说明

    ### Linux信号详解 #### 一、引言 在Linux系统中,信号是一种进程...通过对信号的理解和合理使用,不仅可以提高程序的健壮性,还可以增强系统的稳定性和安全性。希望本文能够帮助读者更好地掌握Linux信号的相关知识。

    coredump文件调试

    常见的信号包括 SIGSEGV、SIGILL、SIGFPE、SIGBUS 等。这些信号通常是由于数组越界、空指针或是野指针读写造成的。 在 C/C++ 程序中,数组越界或是访问空指针都会产生 SIGSEGV 信号,导致进程 crash,并产生 Core ...

    藏经阁-云时代下的 性能优化&运维实践之路.pdf

    1. 应用程序崩溃检测:使用信号捕获机制(EXC_BAD_ACCESS、SIGSEGV、SIGBUS等)来检测应用程序崩溃,通过崩溃日志上报脚本add to build phrase生成日志码力实时告警数据存储,从而实现在应用程序崩溃时快速定位问题...

    Linux信号列表.pdf

    7. SIGBUS:非法地址,包括内存地址对齐(alignment)出错。例如访问一个四个字长的整数,但其地址不是4的倍数。 8. SIGFPE:在发生致命的算术运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等其它所有...

    UNIX_信号说明1

    7. **SIGBUS(非法地址)**:当进程尝试访问内存地址对齐错误或者非法内存区域时发送。这与SIGSEGV的区别在于SIGSEGV通常发生在访问合法但不应访问的内存区域。 8. **SIGFPE(浮点异常)**:当发生算术错误,如除以...

    Squid 中文权威指南(5)

    - **作用**:在调试时很有用,避免 Squid 捕获某些致命信号(如 SIGBUS 和 SIGSEGV),从而可能导致 core dump。 10. **-D** - **功能**:禁用 DNS 测试。 - **作用**:Squid 会在启动前确保 DNS 服务可用,该...

    Linux信号列表[文].pdf

    7) SIGBUS(非法地址):当进程试图访问非法内存地址,如地址对齐错误,系统会发送SIGBUS信号。 8) SIGFPE(浮点异常):在发生算术运算错误,如除零、溢出等时,进程会收到SIGFPE信号。 9) SIGKILL(杀掉):这是...

    9cc:练习从https://www.sigbus.infocompilerbook制作编译器

    9cc是一个开源项目,旨在帮助学习者理解和实践编译器的构建过程。它是一个小型的C语言编译器,由Infocompilerbook的作者在www.sigbus.info上介绍。通过参与9cc的实现,你可以深入理解编译原理,掌握如何将高级语言...

    Android Native Exception

    当发生某些类型的异常时,如SIGSEGV或SIGBUS,为了便于调试,系统可能会生成一个核心转储文件(Coredump)。Coredump文件包含了出错时刻的进程状态信息,包括但不限于: - **信号信息**: 导致异常的信号类型以及信号...

    Linux信号机制的分析与研究.pdf

    - **进程异常事件信号**:如SIGSEGV(段错误)和SIGFPE(算术错误),分别针对非法内存访问和算术运算错误。 - **系统调用失败信号**:例如,SIGBUS(非法地址,包括内存对齐错误)和SIGALRM(时钟定时信号)。 -...

    Linux系统信号处理方法的应用.pdf

    包括系统内核产生的和由其他进程产生的,如SIGHUP(终端挂断)、SIGINT(用户中断)、SIGQUIT(用户退出)、SIGABRT(异常终止)、SIGBUS(总线错误)、SIGKILL(不可忽略的终止进程信号)、SIGUSR1(用户自定义信号...

    Android Native Crash分析详解

    2. **SIGBUS(signal 7)**:非法地址访问,但与SIGSEGV不同之处在于访问的地址虽在进程地址空间内,但未按字节对齐(例如,访问未被2或4整除的地址)。另一种情况是在使用mmap映射文件后,文件被截断但仍尝试访问已...

    Linux应用程序调试之debug_coredump

    - SIGBUS:访问不存在或未对齐的内存地址时发出。 - SIGFPE:执行数学运算错误时发出。 - SIGILL:执行非法指令时发出。 - SIGQUIT:用户通过键盘或其他方式请求退出时发出。 - SIGSYS:无效系统调用时发出。 - ...

    Linux系统编程实验六:进程间通信.doc

    实验器材包括装有Linux的VMware虚拟机和PC机,通过编写和运行相应的C程序,学生可以亲身体验和理解各种进程间通信方法的工作原理和应用场景。 通过这个实验,学生不仅能学习到Linux系统编程的基础知识,还能掌握到...

    libfuckit:尽力而为的 CC++ 错误压路机

    libfuckit安装了SIGSEGV,SIGBUS,SIGABRT,SIGILL和SIGFPE自定义信号处理程序来捕获像分割故障的常见问题,违规操作只要有可能。 它还禁用了 C++ 中的throw ,因此您永远不会因缺少相应的catch(...){}受苦。 ...

    happyday11-信号.docx

    11) SIGSEGV(段错误信号):当进程试图访问未分配给它的内存或只读内存时,系统发送SIGSEGV信号。 12) SIGPIPE(管道破裂信号):当进程向已关闭或未打开的管道写入数据时,会发生SIGPIPE信号,常在进程间通信中...

    unix/linux信号详解大全

    * SIGSEGV:“断违例”信号,在进程访问无效或无权限内存地址时发出。 * SIGSYS:错误的系统调用,比如指示系统调用的参数类型错误等。 * SIGTRAP:在执行了断点指令或其他陷阱指令时发出,主要在调试程序时使用。 *...

Global site tag (gtag.js) - Google Analytics