X86 Linux 下 SIGBUS 總結(jié)
SIGBUS 在 x86 Linux 上并不多見,但一旦出現(xiàn),其調(diào)用堆棧常常讓人摸不著頭腦,加之信號問題各平臺系統(tǒng)間差異較大,更讓人難以理清,這里稍微總結(jié)一下 x86 Linux 上大概有哪些情形會(huì)觸發(fā) BUS ERROR.
文件映射訪問異常##
這是 SIGBUS 在用戶態(tài)最為常見的場景,也最容易觸發(fā),通常來說根本原因都是進(jìn)程 mmap 了一個(gè)文件后,另外的進(jìn)程把這個(gè)文件截?cái)嗔耍瑢?dǎo)致 mmap 出來的某些內(nèi)存頁超出文件的實(shí)際大小,訪問那些超出的內(nèi)存頁就會(huì)觸發(fā) SIGBUS,具體來說有以下幾種場景:
1、進(jìn)程 mmap 一個(gè)文件后,其它進(jìn)程 truncate 該文件到更小。
2、動(dòng)態(tài)庫更新,直接 cp 覆蓋。
3、可執(zhí)行文件更新,直接 cp 覆蓋。
系統(tǒng)讀取磁盤文件通常是按頁映射到內(nèi)存,出于效率考慮常常使用 copy on write 機(jī)制,所以文件映射之后,如果對應(yīng)的文件 page 不存在了(truncated),也不見得會(huì)馬上出問題,只有到訪問時(shí)才會(huì)出錯(cuò),因此有一定滯后期。
訪問不對齊的內(nèi)存##
X86 平臺上訪問不對齊的內(nèi)存時(shí),默認(rèn)不會(huì)有問題,但用戶可以手動(dòng)設(shè)置 EFLAGS 把 CPU 設(shè)置為不允許非對齊的內(nèi)存訪問,此時(shí)如果出現(xiàn)不對齊的內(nèi)存訪問,SIGBUS 就會(huì)拋出,具體例子參看【3】。

Stack fault exception
這種場景非常罕見,通常是 OS 或者內(nèi)存硬件問題,從 intel 的開發(fā)者文件來看,這種異常屬于 trap,并不是我們用戶態(tài)常說的 exception,這種異常有三種起因【4】:
1、canonical address violation.
Canonical address 指的是 64 位模式下,地址的高 48 ~ 64 不是全部是 0 或 1 的地址。
如果通過棧指針 rbp 或 rsp 訪問了非 canonical address 內(nèi)核就會(huì)發(fā) stack fault trap,示例代碼如下:

需要注意的是只有棧指針操作才會(huì) SIGBUS,非棧指針引發(fā)的這類異常,只會(huì)拋 SIGSEG。
2、棧指針操作引用了超出棧大小的地址。
這類操作我還沒法重現(xiàn),只是文檔說了可以觸發(fā)。
3、棧操作引用了不存在的 stack segment。
這類操作通常是內(nèi)核或編譯器的 bug。
綜上可知,stack fault 必然是與 rsp/rbp 這樣的棧指針操作相關(guān),通常用戶態(tài)不大可能觸發(fā),如果不是 mmap 相關(guān)的異常,大多可能是內(nèi)核或硬件問題(這里有些絕對),這類異常通常會(huì)導(dǎo)致內(nèi)核在 /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
浙公網(wǎng)安備 33010602011771號