1. 程式人生 > >一次堆破壞的除錯經歷

一次堆破壞的除錯經歷

過程是這樣的,在vc debug的過程中,突然彈出了一個assert視窗:

Windows has triggered a breakpoint in cs.exe.

This may be due to a corruption of the heap, which indicates a bug in cs.exe or any of the DLLs it has loaded.

This may also be due to the user pressing F12 while cs.exe has focus.

檢視output輸出:

Heap missing last entry in committed range near e664630

Windows has triggered a breakpoint in cs.exe.

This may be due to a corruption of the heap, which indicates a bug in cs.exe or any of the DLLs it has loaded.

不廢話,直接檢視該記憶體是什麼:

0x0E664630  0e 00 0f 00 59 03 10 04 aa aa cd ab 00 10 72 85 38 00

看不出什麼,往上再看看:

0x0E66460C  07 e2 04 00 a8 01 66 0e 01 00 cd cd fd fd fd fd....

看來這就是塊堆記憶體,實在看不出什麼,決定暫時忽略. 過了幾天,該錯誤沒有再出現過.

但就在交付程式前一天測試中,又出現了這個錯誤.看來一顆定時炸彈是埋藏在了程式中.必須找出來,否則後果很嚴重.

首先要做的就是要重現這個問題,如果每次碰巧遇到這個問題的話,實在無從下手.從症狀來看,是個典型的Heap Corrupt.所以先使用工具:pageheap,以做到能夠百分百重現那個堆破壞.

page heap工具啟用的兩種方法:Full-page heap和Normal page heap

我先使用了Normal page heap 命令為pageheap /enable xx.exe /normal

然後通過windbg設定符號表:x:/symbols_folder;srv*x:/symbols_folder*http://msdl.microsoft.com/download/symbols

開始各種除錯,幾乎用遍了<<Windows高階除錯>>這本書中指導的各種命令,(除錯過程省略2000字)未果.幾乎崩潰時,突然看到書上的這麼一段話:

普通頁堆通過填充模式檢測堆塊破壞,需要再發生堆破壞之後再呼叫一次堆管理器.

完全頁堆除了特定的填充模式外,它還為每個堆塊增加了防護頁,防護頁是一個頁不可訪問的記憶體,它被放置在堆塊的起始位置和結束位置上.防止堆塊上下溢位.

我靠,直接pageheap /enable xx.exe /full 設定完全頁堆模式.重新執行程式.

瞬間程式崩掉,這個激動呀.還是第一次看見程式崩掉那麼激動,檢視崩潰的程式碼:

原來是把一個類指標強轉為另一個子類的指標,呼叫了子類的一個函式,但是該類不存在這個函式.同時這個子類函式裡面做了一次bool變數賦值,結果這個值就寫到了堆地址裡面去了.

總結

以後遇到類似問題,直接pageheap full 全開.