知識這東西有時候很奇怪,每次當你重新審視他的時候可能都會有新的收獲。最近為了研究一個內存相關的問題,把windows heap相關的內容又復習了一遍,收獲不小,記錄一下,希望有朋友使用的時候少走些彎路。
老話說的好,知己知彼方可百戰不殆,沒准備就去打仗無異於以卵擊石,后果可想而知,那分析heap的問題需要什么基礎知識呢:
1. Windows 基礎知識,內存模型,什么是堆,堆內存是如何管理的,不了解的,建議學習<windows internals>。
2. 如何調試相關的問題,如何選擇工具,建議學習windbg相關的命令。
3. 如何配置系統,如何啟動頁堆,如何使用gflag。
4. 相關的反匯編知識。
5. 知道如何能找到有用的信息。
好吧,以一個例子來說明:
void CTestPHeapDlg::OnBnClickedOk()
{
char * p;
HANDLE hHeap;
hHeap = HeapCreate(0, 1024, 0);
p=(char*)HeapAlloc(hHeap, 0, 9);
}
假設代碼如上,點擊一下,分配一次內存,同時假設代碼很長,無法通過代碼審查發現在那分配額的內存,如下的步驟可以幫你找到在哪分配的內存:
1. 對這個程序配置gflag開啟完全頁堆。
2. windbg調試器下運行程序。
3. 執行如下步驟:
0:001> !heap -p
Active GlobalFlag bits:
hpa - Place heap allocations at ends of pages
StackTraceDataBase @ 00430000 of size 01000000 with 00000378 traces
PageHeap enabled with options:
ENABLE_PAGE_HEAP
COLLECT_STACK_TRACES
active heaps:
+ 170000
ENABLE_PAGE_HEAP COLLECT_STACK_TRACES
NormalHeap - 270000
HEAP_GROWABLE
0:001> !heap -p -h 170000
_DPH_HEAP_ROOT @ 171000
Freed and decommitted blocks
DPH_HEAP_BLOCK : VirtAddr VirtSize
00174a3c : 0284f000 00002000
00174ba4 : 02851000 00002000
00174b7c : 02853000 00002000
00174b04 : 02855000 00002000
001749ec : 02857000 00002000
00174ab4 : 02859000 00002000
001749c4 : 0285b000 00002000
00173d1c : 0285d000 00002000
0017494c : 0285f000 00002000
00173d94 : 02861000 00002000
0017499c : 027e4000 00002000
Busy allocations
DPH_HEAP_BLOCK : UserAddr UserSize - VirtAddr VirtSize
001744ec : 0282ffe0 00000020 - 0282f000 00002000
001741a4 : 0282dfe0 00000020 - 0282d000 00002000
00174a14 : 028b1ff0 00000010 - 028b1000 00002000
001726ec : 025e8fd8 00000024 - 025e8000 00002000
MSCTF!CSharedBlockNT::`vftable'
00172714 : 025e4ff8 00000008 - 025e4000 00002000
00174a64 : 0289bfe0 00000020 - 0289b000 00002000
00174a8c : 02899fe0 00000020 - 02899000 00002000
001743ac : 0284bff0 0000000c - 0284b000 00002000
00174384 : 02849f88 00000074 - 02849000 00002000
00174334 : 02845f88 00000074 - 02845000 00002000
001742e4 : 02841f88 00000074 - 02841000 00002000
0017124c : 00186ce8 00000314 - 00186000 00002000
00171224 : 00184ce8 00000314 - 00184000 00002000
001711fc : 00182d28 000002d8 - 00182000 00002000
001711ac : 0017efd0 0000002d - 0017e000 00002000
0017115c : 0017afd8 00000022 - 0017a000 00002000
_HEAP @ 270000
_HEAP_LOOKASIDE @ 270688
_HEAP_SEGMENT @ 270640
CommittedRange @ 270680
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
* 00270680 0301 0000 [01] 00270688 01800 - (busy)
00271e88 022f 0301 [10] 00271e90 01170 - (free)
VirtualAllocdBlocks @ 270050
0:001> dt _DPH_BLOCK_INFORMATION 0282ffe0-0x20
ntdll!_DPH_BLOCK_INFORMATION
+0x000 StartStamp : 0xabcdbbbb
+0x004 Heap : 0x00171000
+0x008 RequestedSize : 0x20
+0x00c ActualSize : 0x1000
+0x010 FreeQueue : _LIST_ENTRY [ 0x359 - 0x0 ]
+0x010 TraceIndex : 0x359
+0x018 StackTrace : 0x028c271c
+0x01c EndStamp : 0xdcbabbbb
0:001> dds 0x028c271c
028c271c abcdaaaa
028c273c 7c94b244 ntdll!RtlAllocateHeapSlowly+0x44
028c2740 7c919c0c ntdll!RtlAllocateHeap+0xe64
028c2744 7c9114d6 ntdll!RtlpAllocateDebugInfo+0x49
028c2748 7c911566 ntdll!RtlInitializeCriticalSectionAndSpinCount+0xa9
028c274c 7c91162c ntdll!RtlInitializeCriticalSection+0xf
028c2750 7c96b97c ntdll!RtlpDebugPageHeapCreate+0x191
028c2754 7c93bd16 ntdll!RtlCreateHeap+0x41
028c2758 7c812c9f kernel32!HeapCreate+0x55
028c275c 004136d4 TestPHeap!CTestPHeapDlg::OnBnClickedOk+0x34 [f:\democode\testpheap\testpheap\testpheapdlg.cpp @ 158]
028c2760 78aad602 mfc90ud!_AfxDispatchCmdMsg+0xb2 [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\cmdtarg.cpp @ 82]
028c2764 78aadd4a mfc90ud!CCmdTarget::OnCmdMsg+0x2ea [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\cmdtarg.cpp @ 381]
028c2768 78a83a13 mfc90ud!CDialog::OnCmdMsg+0x23 [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\dlgcore.cpp @ 85]
028c276c 78a45994 mfc90ud!CWnd::OnCommand+0x174 [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 2364]
028c2770 78a44609 mfc90ud!CWnd::OnWndMsg+0x79 [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 1769]
028c2774 78a44552 mfc90ud!CWnd::WindowProc+0x32 [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 1755]
028c2778 78a41970 mfc90ud!AfxCallWndProc+0xf0 [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp @ 240]
028c277c abcdaaaa
看到結果了吧?如下的callstack正是內存分配時的棧,希望對大家有所幫助。
028c271c abcdaaaa
028c273c 7c94b244 ntdll!RtlAllocateHeapSlowly+0x44
028c2740 7c919c0c ntdll!RtlAllocateHeap+0xe64
028c2744 7c9114d6 ntdll!RtlpAllocateDebugInfo+0x49
028c2748 7c911566 ntdll!RtlInitializeCriticalSectionAndSpinCount+0xa9
028c274c 7c91162c ntdll!RtlInitializeCriticalSection+0xf
028c2750 7c96b97c ntdll!RtlpDebugPageHeapCreate+0x191
028c2754 7c93bd16 ntdll!RtlCreateHeap+0x41
028c2758 7c812c9f kernel32!HeapCreate+0x55
028c275c 004136d4 TestPHeap!CTestPHeapDlg::OnBnClickedOk+0x34