2009-12-18 32 views
1

我相信你有很多人都經歷過這個。有時在調試崩潰時添加一行跟蹤和中提琴,崩潰消失。這通常指向內存損壞,並在代碼周圍尋找緩衝區溢出等。更具體地說,即使是單線程應用程序也是如此。調試一個segv

雖然一條線追蹤可以防止碰撞發生?

跟蹤線是一段代碼,所以應該去代碼段,因爲它是隻讀的權利?

它應該對本地執行堆棧沒有影響嗎?它是如何影響指針偏移量以使其他一些內存不會被寫入而不會自我表現的(仍然不好)。

+2

這就是所謂的海森堡。 – 2009-12-18 18:01:57

+0

你在什麼環境下運行代碼?你可以附上代碼,因爲它可以更容易地幫助我們SO'ers? – t0mm13b 2009-12-18 18:31:52

+0

你可能是指「voilà」。 – jldupont 2009-12-18 18:48:54

回答

1

一些人已經提到了時間變化。即使您的代碼是單線程的,您可能會調用API,以您的名義啓動線程,或實現其他形式的異步通信。

至於這種說法來講:

跟蹤線是一段代碼,所以應該到代碼段

這取決於你的跟蹤代碼實際上確實 。即使是一些簡單:

write(0, "Hello, World!\n", 14); 

將在至少添加額外的數據存儲爲字符串常量,這將轉向其他常量數據的位置,並可能更改其他存儲器段開始,影響的位置代碼和/或堆,以及。如果這是對該函數的第一個引用,它將向目標文件添加重定位記錄,這可能會導致內存佈局中的其他移位。

例如,調用fwrite或printf的更復雜的跟蹤調用幾乎肯定會爲臨時緩衝區等分配一些內存。

如果您可以在調試器中運行時重現錯誤(顯然是使用原始代碼),那麼您應該至少能夠確定觸發段錯誤的代碼。如果調試器也導致錯誤發生,您可以考慮啓用核心轉儲,並根據轉儲進行調試。

如果不成功,您可以嘗試使用調試malloc包(有幾個可用)運行代碼。即使「錯誤」沒有重現,你也可能會發現一些不正確的指針操作。

最後建議:在編譯器啓用所有警告的情況下重新編譯代碼,並認真考慮所有生成的警告。請注意,使用gcc,-Wall 而不是會打開所有警告。

0

請參閱here以解答我對另一個SO問題的回答。我不是100%確定你正在運行的是什麼環境,但我猜它是其中一個unix變種......我給出的鏈接演示了一個簡單的技巧,通過連接到signal處理程序並在執行期間的任何時候捕獲SIGSEGV處理程序的代碼,處理程序被攔截並將堆棧跟蹤轉儲到一個文件以供讀取。

希望這可以幫助你追蹤問題, 最好的問候, 湯姆。

1

首先,如果跟蹤包含某種類型的字符串,跟蹤不僅會影響代碼段,還會影響數據段。這可以完全改變你的內存佈局。

如果您的段錯誤是由於您取消引用一些隨機存儲器而引起的,則由於數據如何轉移,具體值可能已更改。如果舊的內存佈局導致您讀取無效的內存地址,則新的內存佈局現在會指向某些有效的內容。

我的一個建議是通過添加跟蹤並使用調試器來停止調試。

+0

不要將常量串入只讀存儲器。特定於實現的位置在哪裏,但通常放置在代碼段中。 – HeretoLearn 2009-12-18 18:47:05

+0

是的,但仍然會影響數據段。如果代碼段更長,數據段的開始可以移動。 – 2009-12-18 20:13:45

+0

Doh,是的,你絕對正確。 – HeretoLearn 2009-12-20 01:32:49