2011-04-28 60 views
5

我只是花了一些時間去追逐一個可以歸結爲以下內容的錯誤。代碼錯誤地覆蓋了堆棧,我認爲它寫了函數調用的返回地址。返回後,程序會崩潰,堆棧將被損壞。在Valgrind的運行程序都將返回一個錯誤,如:如何用Valgrind調試堆棧覆蓋錯誤?

vex x86->IR: unhandled instruction bytes: 0xEA 0x3 0x0 0x0 
==9222== valgrind: Unrecognised instruction at address 0x4e925a8. 

我想,這是因爲返回躍升到一個隨機位置,包含的東西,是不是有效的操作碼86。 (雖然我在某種程度上懷疑這個地址0x4e925a8碰巧在一個可執行頁面中,我想如果情況並非如此,valgrind會拋出一個不同的錯誤。)

我確定問題出在堆棧 - 覆蓋類型,我已經修復它。現在我正在想如何更有效地捕捉這樣的錯誤。顯然,valgrind無法警告我是否在堆棧上重寫了數據,但是當某人寫入堆棧上的返回地址時,它可能會被捕獲。原則上,它可以檢測何時發生類似「推送EIP」的事件(因此它可以標記返回地址在堆棧中的位置)。

我想知道如果有人知道Valgrind或其他什麼可以做到嗎?如果沒有,你能評論其他有關調試這種錯誤類型的建議嗎?

+0

我建議你向valgrind提交一個願望清單bug。 – 2011-04-28 06:03:52

+0

返回地址不是用'push'指令推送的,而是由'call'指令隱式的。這使得它更容易檢測到它的位置。 – 2011-04-28 06:12:50

+0

@Jan Hudec,這將是Valgrind的一個整潔的功能,不是嗎?是的,你說的是'call'推送回信地址是正確的,我這樣寫就是爲了完全清楚。 – Max 2011-04-28 18:58:28

回答

4

如果問題發生確定性不夠,你可以指出的是有它的堆棧被砸(在一個可重複的測試案例)特定的功能,你可以在GDB:

  1. 歇在進入該功能
  2. 找到返回地址的存儲位置(它相對於%ebp(在x86上)(它將%esp的值保留在函數入口處),我不確定是否有任何偏移量)。
  3. 將觀察點添加到該地址。你必須用計算出來的號碼發出watch命令,而不是一個表達式,因爲有了表達式,gdb會在每條指令後嘗試重新評估它,而不是設置一個陷阱,這將會非常緩慢。
  4. 讓函數運行完成。

我還沒有使用gdb7中提供的python支持,但它應該允許自動執行此操作。

+0

感謝您的回答,我會接受,除非我學到更好的東西:) – Max 2011-04-28 18:59:32

5

一般來說,Valgrind檢測堆棧和全局變量中的溢出很弱,不存在。可以說,Valgrind是這項工作的錯誤工具。

如果您位於其中一個受支持的平臺上,使用-fmudflap構建並與-lmudflap鏈接將會爲這些類型的錯誤提供更好的結果。其他文檔here

Udpdate:

在很大程度上6年,因爲這個答案已經改變。在Linux上,找到堆棧(和堆)溢出的工具是AddressSanitizer,最近版本的GCC和Clang支持。

+0

似乎http://www.stlinux.com/devel/debug/mudflap是一個死鏈接。也許這個鏈接可以用來代替:https://gcc.gnu.org/wiki/Mudflap_Pointer_Debugging – bgoodr 2017-01-26 21:08:08

+1

@bgoodr我已經更新了答案:與當前技術水平相比,mudflap要弱得多,並且會帶來更大的內存開銷。 – 2017-01-27 00:59:41

+0

感謝您關於內存開銷的提示! – bgoodr 2017-01-29 04:28:06