段错误 (SIGSEGV) vs 总线错误 (SIGBUS)

当操作系统检测到严重的程序错误,且由于这些错误,程序无法继续执行时,会产生段错误Segmentation fault:SIGSEGV)信号和总线错误Bus error:SIGBUS)信号。


1) 段错误(也称为 SIGSEGV,通常是信号 11)发生在程序试图读写分配给它的内存之外的内存时,或者试图写入只读内存时。换言之,当程序尝试访问它没有权限访问的内存时,就会发生段错误。SIGSEGV 是“Signal Segmentation Violation”的缩写。
产生 SIGSEGV 信号的一些情况如下:
-> 使用未初始化的指针
-> 对空指针进行解引用(De-referencing)
-> 试图访问程序不拥有的内存(例如,试图访问数组界限之外的数组元素)
-> 试图访问已经被释放的内存(试图使用悬空指针(dangling pointers))。

段错误例子可以看这篇文章


2)总线错误(也称为 SIGBUS,通常是信号 10)发生在进程尝试访问 CPU 无法物理寻址的内存时。换句话说,程序试图访问的内存不是有效的内存地址。这通常是由于 CPU 的对齐问题导致的(例如,尝试从一个不是 4 的倍数的地址读取长整型(long)数据)。SIGBUS 是“Signal Bus Error”的缩写。

SIGBUS 信号在以下情况下发生:
-> 程序指示 CPU 读取或写入一个特定的物理内存地址,但这个地址是无效的,或统无法识别所者整个计算机系请求的物理地址
-> 内存访问未对齐(例如,如果多字节访问必须 16 位对齐,那么以字节为单位的地址 0、2、4、6 等会被视为对齐的,因此可以访问,而地址 1、3、5 等则被视为未对齐的。)
段错误和总线错误的主要区别在于,段错误表示对有效内存的无效访问,而总线错误则表示对无效地址的访问。

以下是来自维基百科的一个总线错误的示例:

// 演示总线错误的C程序
#include <stdlib.h>
 
int main(int argc, char **argv) 
{
    
#if defined(__GNUC__)
# if defined(__i386__)
    /* 在x86上启用对齐检查 */
    __asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__) 
     /* 在x86_64上启用对齐检查 */
    __asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif
 
    /* malloc() 总是提供内存对齐 */
    char *cptr = malloc(sizeof(int) + 1);
     
    /* 将指针增加一,使其不对齐 */
    int *iptr = (int *) ++cptr;
 
    /* 将其解引用为整型指针,导致未对齐访问 */
    *iptr = 42;
 
    /* 下面的访问会导致 sigbus error(总线错误)
       short *sptr;
       int    i;
 
       sptr = (short *)&i;
 
       // 对于所有奇数值的增量,都会导致 sigbus(总线错误)
       sptr = (short *)(((char *)sptr) + 1);
       *sptr = 100;    */
 
    return 0;
}

英文没问题的,可以直接看原文:icon-default.png?t=N7T8https://www.geeksforgeeks.org/segmentation-fault-sigsegv-vs-bus-error-sigbus/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值