总线错误和段错误有什么区别?一个程序第一次出现段错误导致停止,第二次出现总线错误并退出,这种情况可能发生吗?
总线错误和段错误有什么区别?一个程序第一次出现段错误导致停止,第二次出现总线错误并退出,这种情况可能发生吗?
在我使用的大多数架构上,二者的区别在于:
mmap()
映射一个文件,并尝试访问超出文件末尾的映射缓冲区的部分,或者出现空间不足等错误条件,SIGBUS
信号也会被触发。如果你使用sigaction()
注册了一个信号处理程序,并设置了SA_SIGINFO
,那么你的程序可能可以检查需要处理的内存地址,只处理与内存映射文件有关的错误。因此,你的情况可能是有两个错误,第一个错误有时会导致SIGSEGV,第二个错误(如果程序没有崩溃且仍在运行)会导致SIGBUS。
我建议你使用调试器逐步调试,并注意观察鳄鱼。
#include <stdlib.h>
char array[10];
int main(int argc, char *argv[]) {
return array[atol(argv[1])];
}
$ ./bus_segv -4129
Segmentation fault: 11
$ ./bus_segv -4128
...
$ ./bus_segv 24543
$ ./bus_segv 24544
Bus error: 10
...
$ ./bus_segv 28639
Bus error: 10
$ ./bus_segv 28640
...
$ ./bus_segv 45023
$ ./bus_segv 45024
Bus error: 10
...
$ ./bus_segv 53215
Bus error: 10
$ ./bus_segv 53216
...
$ ./bus_segv 69599
$ ./bus_segv 69600
Bus error: 10
...
$ ./bus_segv 73695
Bus error: 10
$ ./bus_segv 73696
...
$ ./bus_segv 77791
$ ./bus_segv 77792
Segmentation fault: 11
如果你查看反汇编代码,你会发现总线错误范围的边界并不像索引出现的那么奇怪:
$ otool -tv bus_segv
bus_segv:
(__TEXT,__text) section
_main:
0000000100000f60 pushq %rbp
0000000100000f61 movq %rsp, %rbp
0000000100000f64 subq $0x10, %rsp
0000000100000f68 movl $0x0, -0x4(%rbp)
0000000100000f6f movl %edi, -0x8(%rbp)
0000000100000f72 movq %rsi, -0x10(%rbp)
0000000100000f76 movq -0x10(%rbp), %rsi
0000000100000f7a movq 0x8(%rsi), %rdi
0000000100000f7e callq 0x100000f94 ## symbol stub for: _atol
0000000100000f83 leaq 0x96(%rip), %rsi
0000000100000f8a movsbl (%rsi,%rax), %eax
0000000100000f8e addq $0x10, %rsp
0000000100000f92 popq %rbp
0000000100000f93 retq
通过 leaq 0x96(%rip), %rsi
,rsi成为数组起始地址的(相对于PC确定的)地址:
rsi = 0x100000f8a + 0x96 = 0x100001020
rsi - 4128 = 0x100000000 (below segmentation fault)
rsi + 24544 = 0x100007000 (here and above bus error)
rsi + 28640 = 0x100008000 (below bus error)
rsi + 45024 = 0x10000c000 (here and above bus error)
rsi + 53216 = 0x10000e000 (below bus error)
rsi + 69600 = 0x100012000 (here and above bus error)
rsi + 73696 = 0x100013000 (below bus error)
rsi + 77792 = 0x100014000 (here and above segmentation fault)
lldb
可能会针对进程设置不同的页面限制。在调试会话中,我无法重现任何总线错误。因此,调试器可能是避免二进制文件出现总线错误的一种解决方法。
安德烈亚斯
我假设你所说的是Posix定义的SIGSEGV
和SIGBUS
信号。
SIGSEGV
发生在程序引用无效地址时。SIGBUS
是一种实现定义的硬件故障。这两个信号的默认操作是终止程序。
程序可以捕获这些信号,甚至忽略它们。
那么这与什么是总线错误?是重复的。Can it happen that a program gives a seg fault and stops for the first time and for the second time it may give a bus error and exit ?
当然,如果按照字面意思理解这个问题的话...
#include <signal.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int main() {
srand(time(NULL));
if (rand() % 2)
kill(getpid(), SIGBUS);
else
kill(getpid(), SIGSEGV);
return 0;
}
Tada,一个程序可以在一次运行中因分段错误而退出,在另一次运行中因总线错误而退出。