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文檔

相關文章
相關標籤/搜索