X86 Linux 下 SIGBUS 总结

SIGBUS 在 x86 Linux 上并很少见,但一旦出现,其调用堆栈经常让人摸不着头脑,加之信号问题各平台系统间差别较大,更让人难以理清,这里稍微总结一下 x86 Linux 上大概有哪些情形会触发 BUS ERROR.linux

文件映射访问异常

这是 SIGBUS 在用户态最为常见的场景,也最容易触发,一般来讲根本缘由都是进程 mmap 了一个文件后,另外的进程把这个文件截断了,致使 mmap 出来的某些内存页超出文件的实际大小,访问那些超出的内存页就会触发 SIGBUS,具体来讲有如下几种场景:
一、进程 mmap 一个文件后,其它进程 truncate 该文件到更小。
二、动态库更新,直接 cp 覆盖。
三、可执行文件更新,直接 cp 覆盖。debug

系统读取磁盘文件一般是按页映射到内存,出于效率考虑经常使用 copy on write 机制,因此文件映射以后,若是对应的文件 page 不存在了(truncated),也不见得会立刻出问题,只有到访问时才会出错,所以有必定滞后期。指针

访问不对齐的内存

X86 平台上访问不对齐的内存时,默认不会有问题,但用户能够手动设置 EFLAGS 把 CPU 设置为不容许非对齐的内存访问,此时若是出现不对齐的内存访问,SIGBUS 就会抛出,具体例子参看【3】。blog

Stack fault exception

这种场景很是罕见,一般是 OS 或者内存硬件问题,从 intel 的开发者文件来看,这种异常属于 trap,并非咱们用户态常说的 exception,这种异常有三种原由【4】:
一、canonical address violation.
Canonical address 指的是 64 位模式下,地址的高 48 ~ 64 不是所有是 0 或 1 的地址。
若是经过栈指针 rbp 或 rsp 访问了非 canonical address 内核就会发 stack fault trap,示例代码以下:进程

须要注意的是只有栈指针操做才会 SIGBUS,非栈指针引起的这类异常,只会抛 SIGSEG。
二、栈指针操做引用了超出栈大小的地址。
这类操做我还无法重现,只是文档说了能够触发。
三、栈操做引用了不存在的 stack segment。
这类操做一般是内核或编译器的 bug。内存

综上可知,stack fault 必然是与 rsp/rbp 这样的栈指针操做相关,一般用户态不大可能触发,若是不是 mmap 相关的异常,大多多是内核或硬件问题(这里有些绝对),这类异常一般会致使内核在 /var/log/messages 下输出以下一条消息:开发

引用

[1] https://stackoverflow.com/questions/2089167/debugging-sigbus-on-x86-linux
[2] http://orchistro.tistory.com/206
[3] https://sourceware.org/bugzilla/show_bug.cgi?id=11357
[4] https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf文档

相关文章
相关标签/搜索