GFlags 檢查記憶體越界、野指標等作用的工具使用
開啟檢查功能: gflags /p /enable **.exe /full
關閉檢查功能: gflags /p /disable **.exe
列出當前啟動了頁堆的程序列表 : gflags /p
1. 案例
除錯執行,程式退出時崩潰在
ntdll
中的一個函式中,
output
視窗中輸出:
HEAP: Free Heap block xxxxxx modified at xxxxxx after it was freed
此時,無法快速找出程式哪裡出現了記憶體非法訪問。
2. 解決方法 a. 安裝
b. 執行: gflags -p /enable ***.exe /full
"***.exe" 為需要除錯的程式名稱,不需要完整路徑。 該命令列會在登錄檔裡設定一些除錯引數 , 使記憶體在使用的時候加入了保護機制 , 一旦記憶體寫 越界 , 或者發生野指標的問題 , 都會導致一箇中斷。由此 , 就可以確定問題到底出在哪裡了。 |
配置正常頁堆:
"C:/Program Files/Debugging Tools for Windows (x86)/gflags.exe" /p /enable qq.exe
配置完全頁堆:
"C:/Program Files/Debugging Tools for Windows (x86)/gflags.exe" /p /enable qq.exe /full
列出當前啟動了頁堆的程序列表:
"C:/Program Files/Debugging Tools for Windows (x86)/gflags.exe" /p
取消頁堆設定:
"C:/Program Files/Debugging Tools for Windows (x86)/gflags.exe" /p /disable qq.exe
c.
除錯執行自己的程式,此時
Visual C++
d. 刪除登錄檔中的除錯設定: gflags -p /disable ***.exe
什麼是 Page Heap (頁堆)?
從 Windows 2000 開始作業系統開始在堆管理器引入“校驗層”,即 Page Heap 管理器。這個校驗層處於 Ntdll.dll 模組內。可以驗證應用程式所有的動態記憶體操作(讀寫、分配、釋放及其它操作)。
頁堆有兩種型別:正常頁堆和完全頁堆( Full Page Heap )
完全頁堆:
當分配一塊記憶體時,通過調整記憶體塊的分配位置,使其結尾恰好與系統分頁邊界對齊,然後在邊界處再多分配一個不可訪問的頁作為保護區域。這樣,一旦出現記憶體讀 / 寫越界時,程序就會 Crash ,從而幫助及時檢查記憶體越界。
因為每次分配的記憶體都要以這種形式佈局,尤其對於小片的記憶體分配,即使分配一個位元組,也要分配一個記憶體頁,和一個保留的虛擬記憶體頁(注意在目前的實現中,這個用作邊界保護區域的頁從來不會被提交)。這就需要大量的記憶體,到底一個程序需要多少記憶體,很難估算,因此在使用 Page Heap 前,至少保證你的機器至少設定了 1G 虛擬記憶體以上。
正常頁堆
正常頁堆原理與 CRT 除錯記憶體分配函式類似,通過分配少量的填充資訊,在釋放記憶體塊時檢查填充區域。來檢測記憶體是否被損壞,此方法的優點是極大的減少了記憶體耗用量。缺點是隻能在釋放塊時檢測,不太好跟蹤出錯的程式碼位置。
GFlags 、 AppVerifier 、 Pageheap.exe
GFlags 、 AppVerifier 、 Pageheap.exe 是三種外殼工具,都是用來方便使用者配置 Page heap 選項的。 Page Heap 選項位於登錄檔目錄: HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Image File Execution Options/ 你的可執行程式名 / 。當 Windows 開始啟動一個程序時, Window 通過檢查這個登錄檔目錄的設定,對該程序應用相應的 PageHeap 選項。
Pageheap.exe
- PageHeap 配置工具,在 Windows 2000 Professional SP2 以上可用。已經被 GFlags 取代。
GFlags
- 老牌的 PageHeap 配置工具,有命令列和 GUI 兩種操作方式,功能比較全,包含在 Windbg 偵錯程式安裝包內。同樣在 Windows 2000 Professional SP2 以上可用。
AppVerifier
- 新的 PageHeap 配置工具,需要 XP 系統才支援。 VS2005 內建了 AppVerifier, 支援,用“ Debug ”選單—〉“ Start With Application Verifier ”啟動程式,會自動啟動 Page Heap 。下載: http://www.microsoft.com/downloads/details.aspx?FamilyID=bd02c19c-1250-433c-8c1b-2619bd93b3a2&displaylang=en#filelist
一些使用 GFlags 命令列的例子:
一定需要這些工具嗎?
正如前面提到的, PageHeap 屬於作業系統提供的功能,這幾個工具只是方便修改登錄檔中的選項,在實際應用中可以通過直接修改登錄檔來啟用 PageHeap 。這在客戶的機器上很有用,不再要求客戶去安裝這些軟體。
一些特殊選項解釋:
/unaligned
這個選項只能用於完全頁堆。當我們從普通堆管理器分配一塊記憶體時,記憶體總是 8 位元組對齊的,頁堆預設情況下也會使用這個對齊規則,但是這會導致分配的記憶體塊的結尾不能跟頁邊界精確對齊,可能存在 0-7 個位元組的間隙,顯然,對位於間隙範圍內的訪問是不會被立即發現。更準確的說,讀操作將永遠不能被發現,寫操作則要等到記憶體塊釋放時校驗間隙空間內的填充資訊時才發現。 /unaligned 用於修正這個缺陷,它指定頁堆管理器不必遵守 8 位元組對齊規則,保證記憶體塊尾部精確對齊頁邊界。
需要注意的是,一些程式啟用這個選項可能出現異常,例如 IE 和 QQ 就不支援。
/backwards
這個選項只能用於完全頁堆。這個選項使得分配的記憶體塊頭部與頁邊界對齊(而不是尾部與邊界對齊),通過這個選項來檢查頭部的訪問越界。
/debug
指定一啟動程序即 Attach 到偵錯程式,對於那些不能自動生成 dump 的程式,是比較有用的選項。
頁堆能校驗的有效範圍
所有記憶體分配函式,只要最終呼叫到 ntdll.Dll 堆管理函式(即 RtlAllocateHeap , RtlFreeHeap ),頁堆都是有效的。具體包括:
諸如 HeapAlloc 、 HeapFree 、 HeapReAlloc 、 LocalAlloc 、 LocalFree 、 LocalReAlloc 等等 Kernel32 提供的堆管理函式。
CRT 記憶體分配如: malloc 、 free 、 realloc 、 msize 、 expand 、運算子 new 、 delete 、 new[ ] 、 delete[ ] 等等。
但頁堆不能用於驗證虛擬記憶體分配函式如: VirtualAlloc 、 VirtualFree 等分配的記憶體塊。
頁堆能處理的錯誤型別:
錯誤型別 正常頁堆 整頁堆
堆控制代碼無效 立即發現 立即發現
堆記憶體塊指標無效 立即發現 立即發現
多執行緒訪問堆不同步 立即發現 立即發現
假設重新分配返回相同地址 (realloc) 90% 記憶體釋放後發現 90% 立即發現
記憶體塊重複釋放 90% 立即發現 90% 立即發現
訪問已釋放的記憶體塊 90% 在實際釋放後發現 90% 立即發現
訪問塊結尾之後的內容 在釋放後發現 立即發現
訪問塊開始之前的內容 在釋放後發現 立即發現