X86 Linux 下 SIGBUS 总结
SIGBUS 在 x86 Linux 上并不多见,但一旦出现,其调用堆栈常常让人摸不着头脑,加之信号问题各平台系统间差异较大,更让人难以理清,这里稍微总结一下 x86 Linux 上大概有哪些情形会触发 BUS ERROR.
文件映射访问异常##
这是 SIGBUS 在用户态最为常见的场景,也最容易触发,通常来说根本原因都是进程 mmap 了一个文件后,另外的进程把这个文件截断了,导致 mmap 出来的某些内存页超出文件的实际大小,访问那些超出的内存页就会触发 SIGBUS,具体来说有以下几种场景:
1、进程 mmap 一个文件后,其它进程 truncate 该文件到更小。
2、动态库更新,直接 cp 覆盖。
3、可执行文件更新,直接 cp 覆盖。
系统读取磁盘文件通常是按页映射到内存,出于效率考虑常常使用 copy on write 机制,所以文件映射之后,如果对应的文件 page 不存在了(truncated),也不见得会马上出问题,只有到访问时才会出错,因此有一定滞后期。
访问不对齐的内存##
X86 平台上访问不对齐的内存时,默认不会有问题,但用户可以手动设置 EFLAGS 把 CPU 设置为不允许非对齐的内存访问,此时如果出现不对齐的内存访问,SIGBUS 就会抛出,具体例子参看【3】。
Stack fault exception
这种场景非常罕见,通常是 OS 或者内存硬件问题,从 intel 的开发者文件来看,这种异常属于 trap,并不是我们用户态常说的 exception,这种异常有三种起因【4】:
1、canonical address violation.
Canonical address 指的是 64 位模式下,地址的高 48 ~ 64 不是全部是 0 或 1 的地址。
如果通过栈指针 rbp 或 rsp 访问了非 canonical address 内核就会发 stack fault trap,示例代码如下:
需要注意的是只有栈指针操作才会 SIGBUS,非栈指针引发的这类异常,只会抛 SIGSEG。
2、栈指针操作引用了超出栈大小的地址。
这类操作我还没法重现,只是文档说了可以触发。
3、栈操作引用了不存在的 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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)