分段错误(SIGSEGV)和总线错误(SIGBUS)是操作系统检测到严重的程序错误并且由于这些错误而无法继续执行程序时生成的信号。
1)分段错误(也称为SIGSEGV,通常为信号11)是在程序尝试在为其分配的内存之外进行写/读或仅写可读取的内存时发生的,换句话说,当程序尝试访问它无法访问的内存。 SIGSEGV是“分段违规”的缩写。生成SIGSEGV信号的情况很少,如下所示:
->使用未初始化的指针
->取消引用NULL指针
->尝试访问程序不拥有的内存(例如,尝试访问数组元素
超出数组范围)。
->尝试访问已取消分配的内存(尝试使用悬空指针)。
请参考本文的示例。
2)当某个进程试图访问CPU无法物理寻址的内存时,就会发生总线错误(也称为SIGBUS,通常是信号10),换句话说,程序试图访问的内存不是有效的内存地址。这是由于CPU对齐问题引起的(例如,尝试从非4的倍数的地址中读取很长的整数)。 SIGBUS是“总线错误”的代名词。
在以下情况下会发生SIGBUS信号,
->程序指示CPU读取或写入无效的特定物理内存地址/整个计算机系统无法识别所请求的物理地址。
->内存的未对齐访问(例如,如果多字节访问必须进行16位对齐,则0、2、4、6等处的地址(以字节为单位)等将被视为对齐,因此可访问,而地址1、3、5等将被视为未对齐。)
分段错误和总线错误之间的主要区别在于,分段错误指示对有效内存的无效访问,而总线错误指示对无效地址的访问。
以下是来自维基百科的公交车错误示例。
// C program to demonstrate Bus Error
#include
int main(int argc, char **argv)
{
#if defined(__GNUC__)
# if defined(__i386__)
/* Enable Alignment Checking on x86 */
__asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__)
/* Enable Alignment Checking on x86_64 */
__asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif
/* malloc() always provides aligned memory */
char *cptr = malloc(sizeof(int) + 1);
/* Increment the pointer by one, making it
misaligned */
int *iptr = (int *) ++cptr;
/* Dereference it as an int pointer, causing
an unaligned access */
*iptr = 42;
/* Following accesses will also result in
sigbus error.
short *sptr;
int i;
sptr = (short *)&i;
// For all odd value increments, it will
// result in sigbus.
sptr = (short *)(((char *)sptr) + 1);
*sptr = 100; */
return 0;
}
输出 :
Bad memory access (SIGBUS)