当操作系统检测到严重的程序错误,且由于这些错误,程序无法继续执行时,会产生段错误 (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;
}
英文没问题的,可以直接看原文:https://www.geeksforgeeks.org/segmentation-fault-sigsegv-vs-bus-error-sigbus/