2012-12-02 146 views
1

最近我遇到了段錯誤問題,它在調用delete方法時被擊中。我已深入檢查了代碼,並消除了刪除空指針,多次刪除或超出限制的可能性(分配的內存足夠大以容納之後寫入的內容)。這個問題可以被複制,每次它在同一個地方發生段錯誤。段錯誤代碼的可能原因是什麼

我想盡辦法可能會導致此問題。我不知道是否有可能得到錯誤代碼的一些線索,我得到,如: - 段錯誤的XXXXXXXXXXXXXX撕裂XXXXXXXXXXXXXX RSP XXXXXXXXXXXXXX錯誤4

我搜索過網了相當長的時間,只得到有用以下信息來自stackoverflow: -

「錯誤代碼只是頁面錯誤的體系結構錯誤代碼,似乎是特定於體系結構的,它們通常記錄在內核源代碼的arch/*/mm/fault.c中。 Linux/arch/i386/mm/fault.c的副本具有以下error_code的定義:

bit 0 == 0 means no page found, 1 means protection fault 
bit 1 == 0 means read, 1 means write 
bit 2 == 0 means kernel, 1 means user-mode 

這是我的問題: - 錯誤代碼4(我的平臺是RHEL5 64位,x86_64)的可能原因是什麼?有什麼辦法可以從錯誤代碼中知道可能的原因嗎?

有關如何診斷這類問題的任何其他建議也受到讚賞!

+2

在'valgrind'下運行你的程序。 –

+0

刪除空指針不是問題。 – ldav1s

回答

1

鑑於您提供的arch/i386/mm/fault.c的文檔,錯誤代碼4對應於「未找到頁面的用戶模式讀取」。代碼4的二進制表示= 100,其中位2是最重要的(最左邊的)位。

這種伴隨着delete接收SIGSEGV的最常見原因:雙免費(試圖釋放已被釋放的指針)。但是,任何堆損壞(例如,通過雙重釋放別的東西或在其他地方出現緩衝區溢出/越界錯誤)可能是原因。

嘗試在valgrind下運行代碼(使用調試版本的內存分配例程運行)(在運行二進制文件之前在環境中將MALLOC_CHECK_設置爲1或2),這兩種方法都嘗試抓住這些錯誤並在製作完成後儘快向您報告。

valgrind在其存儲器模型中是詳盡的,並且在適當的檢查開啓的情況下,幾乎可以肯定定位問題的根源。

MALLOC_CHECK_是glibc的內部函數,並且與大多數不是valgrind的大多數其他內存調試工具工具一樣,它只能捕獲某些類型的相對常見錯誤並在某些情況下檢測堆損壞。有很多其他工具,例如MALLOC_CHECK_(例如Electric Fence),但前者已經內置到您的C庫中,其他工具至多會要求其庫(主要包含mallocfree覆蓋,主要)在使用LD_PRELOAD的C庫之前動態鏈接。

請注意,在空指針上使用C++ delete在技術上不是問題,所以您可以從清單中刪除一個(因爲我猜你可能已經擁有了,通過修改代碼以在刪除之前顯式檢查) 。

更多細節:

對應的錯誤代碼「讀未找到的頁面的用戶模式」意味着一個指針,指向存儲器(一些64分之32位數字參照某處在虛擬地址空間)被解除引用(即,某些代碼嘗試讀取指針所保存的虛擬內存地址處的值),但內核頁表指示虛擬地址引用的內存頁面未被映射到您的進程中,或者已從您的流程中取消映射,因爲該指針是有效的。除了想象這種情況的明顯方式之外,它可以間接發生,因爲堆損壞(其中包含幕後的各種簿記信息):例如,指針算術可以根據傳遞給delete與堆內部的另一個較早損壞的指針進行比較,然後導致位於指針中的無效值,只是等待代碼嘗試並使用它。

換句話說,內核錯誤代碼在常見的調試場景中確實沒有什麼幫助。

我假設你已經在gdb下運行你的程序,並且只需在崩潰前的幾行設置一個斷點,以觀察指針被刪除的值以及周圍狀態的其餘部分。

編輯:

刪除錯誤-g2參考,當我顯然意味着MALLOC_CHECK_。爲您添加了更多的診斷問題和解釋。

+0

您的意思是,如果原因位於其他位置,則在編譯代碼時添加-g2開關可能會在程序出錯時強制程序提前中止?但據我所知,-g2開關會將符號添加到二進制文件中,從來沒有聽說它會進行這種類型的檢查,有沒有對此提及? – user1137890

+0

我知道,我們可以導出MALLOC_CHECK_以在程序中存在內存損壞時強制程序提前中止。我認爲如果這個問題是由其他地方的內存腐敗引起的,那麼這也是一個不錯的選擇,你對此有何看法?順便說一句,在我的情況下,我無法自由訪問環境,並且這個問題不能在我的環境中重現(在所討論的環境中也不能100%重現)。所以Valgrind不是一個好選擇。我需要找到一些簡單可行的方法來做到這一點。 – user1137890

+0

@ user1137890我的意思是,如果在編譯代碼時添加'-g2'(而不是僅僅打開調試符號的'-g'),GCC將打開其調試堆分配器和各種其他運行時錯誤檢測工具選項。這會做類似於你描述的'MALLOC_CHECK_'的東西,這也許是一個很好的選擇,你也應該嘗試一下。如果這個錯誤還不能被重現,那麼這就是懷疑堆損壞的更多理由,在大多數情況下,在運行時第一個內存錯誤點(使用這些工具)可能會檢測到堆損壞,而不是在損壞之後很長時間。 –

相關問題