堆破壞(Heap Corruption)和Gflags
什麼是Heap Corruption
堆破壞是記憶體破壞的一種,簡單來說就是由於程式的錯誤導致堆記憶體被意外改寫,典型的情況包括:
- 申請了N個Bytes的記憶體,卻試圖寫入> N個Bytes的內容;
- 向已經釋放的記憶體位置寫入內容;
fFrameSize=pSearch01To-fpBuffer; //在某種情況下會出現fFrameSize = 0xFFFFFFFCmemcpy(fTo,fpBuffer,fFrameSize); //這裡memcpy會發生什麼?
Heap Corruption的危害
把不屬於自己的記憶體塊的內容改寫掉,危害是很顯然的。更要命的是,Heap Corruption的問題往往很難排查,因為:
- 每次執行表現出來的現象可能不一樣;
- Debug版和Release版表現可能不一樣;
- 問題暴露的地方和問題引入的地方可能相差很遠,兩者邏輯上沒有必然聯絡;
PageHeap檢測Heap Corruption的原理
PageHeap工具可以在執行時檢測Heap Corruption,其基本原理是在我們分配的記憶體塊前後加上一些額外資訊,這些額外資訊用以檢測是否出現越界寫的情況。PageHeap分為Full模式和Normal模式:
- Full模式:在我們分配的每個記憶體塊尾上加一頁non-accessible page。Full模式的好處是“Sudden
Death”,即在問題發生的點上立馬Access Violation,易於
- Normal模式:在我們分配的每個記憶體塊前後加少量的填充欄位。Normal模式的好處是記憶體消耗較少。壞處是隻有在釋放記憶體時才會檢測出Heap Corruption,Debugging難度還是比較大。
PageHeap的使用方法
大家在WinDbg的安裝路徑下,可以看到gflags.exe這個工具,gflags集成了pageheap的功能。Gflags可以以GUI方式或Console方式執行,但是GUI方式只能啟用PageHeap的Full模式,所以建議大家通過Console方式來使用gflags(以Run As Administrator方式開啟
幾條基本命令如下:
Gflags.exe /p /enable dest.exe
Gflags.exe /p /disable dest.exe
Gflags.exe /p
具體使用方法可以在WinDbg的幫助文件中搜索PageHeap,或在命令列模式下gflags /p /?
其他相關工具
除了gflags\pageheap之外,Application Verifier也可以用來檢測Heap Corruption問題。Application Verifier也包含了其他很多執行時檢查項,大家可以在工作中按需使用。Application Verifier的問題是它不支援託管程式碼。
寫程式過程中預防Heap Corruption
PageHeap、Application Verifier或其他的執行時檢查工具其實都是事後諸葛亮;對我們來說更重要的是在每天寫程式的過程中就控制住,不給Heap Corruption機會。控制方法不止一種,就我們目前的情況來說,有兩點是可以立即做的:
- Klocwork靜態程式碼檢查:Klocwork不能幫我們查出所有的Heap Corruption,但實踐證明還是能查出一部分的;
- 使用安全的函式:就是xxx_s,如memcpy_s等;對於我們自己寫的涉及記憶體操作的函式,也應設計成安全的。