Dela via


Exempel 12: Använda page heap-verifiering för att hitta en bugg

Följande serie kommandon visar hur du använder verifieringsfunktionerna för sid heap i GFlags och NTSD-felsökaren för att identifiera ett fel vid heapminnesanvändning. I det här exemplet misstänker programmeraren att ett fiktivt program, pheap-buggy.exe, har ett heapfel och fortsätter genom en serie tester för att identifiera felet.

Mer information om NTSD finns i felsökning med hjälp av CDB och NTSD.

Steg 1: Aktivera standardverifiering av sidhögar

Följande kommando aktiverar standardverifiering av sid heap för pheap-buggy.exe:

gflags /p /enable pheap-buggy.exe

Steg 2: Kontrollera att sidhögen är aktiverad

Följande kommando listar bildfiler för vilka sidheap-verifiering är aktiverad:

gflags /p

Som svar visar GFlags följande lista över program. I den här vyn anger spårningar standard heapverifiering för sidor, och fullständiga spårningar anger fullständig heapverifiering för sidor. I det här fallet visas pheap-buggy.exe med spår som anger att standardverifiering av sidminneshög är aktiverad, vilket är avsett.

pheap-buggy.exe: page heap enabled with flags (traces )

Steg 3: Kör felsökningsprogrammet

Följande kommando kör funktionen CorruptAfterEnd för pheap-buggy.exe i NTSD med parametrarna -g (ignorera inledande brytpunkt) och -x (ange andra chansens avbrott i undantag för åtkomstöverträdelser):

ntsd -g -x pheap-buggy CorruptAfterEnd

När programmet misslyckas genererar NTSD följande visning, vilket indikerar att det upptäckte ett fel i pheap-buggy.exe:

===========================================================
VERIFIER STOP 00000008: pid 0xAA0: corrupted suffix pattern

        00C81000 : Heap handle 
        00D81EB0 : Heap block 
        00000100 : Block size 
#         00000000 :
===========================================================

Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00d81eb0 ecx=77f7e257 edx=0006fa18 esi=00000008 edi=00c81000
eip=77f7e098 esp=0006fc48 ebp=0006fc5c iopl=0         nv up ei pl zr na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000246
ntdll!DbgBreakPoint:
77f7e098 cc               int     3

Rubrikinformationen innehåller adressen till heapen med det skadade blocket (00C81000 : Heap handle), adressen till det skadade blocket (00D81EB0 : Heap block) och storleken på allokeringen (00000100 : Blockstorlek).

Meddelandet "skadat suffixmönster" anger att programmet bröt mot dataintegritetsmönstret som GFlags infogade efter slutet av pheap-buggy.exe heap-allokering.

Steg 4: Visa anropsstacken

I nästa steg använder du adresserna som NTSD rapporterade för att hitta funktionen som orsakade felet. De följande två kommandona aktiverar radnummerdumpning i felsökningsprogrammet och visar anropsstacken med radnummer.

C:\>.lines

Line number information will be loaded 

C:\>kb

ChildEBP RetAddr  Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0006fc5c 77f9e6dd 00000008 77f9e3e8 00c81000 ntdll!DbgBreakPoint
0006fcd8 77f9f3c8 00c81000 00000004 00d81eb0 ntdll!RtlpNtEnumerateSubKey+0x2879
0006fcfc 77f9f5bb 00c81000 01001002 00000010 ntdll!RtlpNtEnumerateSubKey+0x3564
0006fd4c 77fa261e 00c80000 01001002 00d81eb0 ntdll!RtlpNtEnumerateSubKey+0x3757
0006fdc0 77fc0dc2 00c80000 01001002 00d81eb0 ntdll!RtlpNtEnumerateSubKey+0x67ba
0006fe78 77fbd87b 00c80000 01001002 00d81eb0 ntdll!RtlSizeHeap+0x16a8
0006ff24 010013a4 00c80000 01001002 00d81eb0 ntdll!RtlFreeHeap+0x69
0006ff3c 01001450 00000000 00000001 0006ffc0 pheap-buggy!TestCorruptAfterEnd+0x2b [d:\nttest\base\testsrc\kernel\rtl\pageheap\pheap-buggy.cxx @ 185]
0006ff4c 0100157f 00000002 00c65a68 00c631d8 pheap-buggy!main+0xa9 [d:\nttest\base\testsrc\kernel\rtl\pageheap\pheap-buggy.cxx @ 69]
0006ffc0 77de43fe 00000000 00000001 7ffdf000 pheap-buggy!mainCRTStartup+0xe3 [crtexe.c @ 349]
0006fff0 00000000 0100149c 00000000 78746341 kernel32!DosPathToSessionPathA+0x204

Därför visar felsökningsprogrammet anropsstacken för pheap-buggy.exe med radnummer. Anropsstacken visar att felet inträffade när funktionen TestCorruptAfterEnd i pheap-buggy.exe försökte frigöra en allokering på 0x00c80000 genom att anropa HeapFree, en omdirigering till RtlFreeHeap.

Den troligaste orsaken till det här felet är att programmet skrev förbi slutet av bufferten som det allokerade i den här funktionen.

Steg 5: Aktivera heap-verifiering för hela sidan

Till skillnad från standardverifiering av sidhögar kan fullständig heap-verifiering fånga missbruket av den här heapbufferten så snart den inträffar. Följande kommando aktiverar fullständig sid heap-verifiering för pheap-buggy.exe:

gflags /p /enable pheap-buggy.exe /full

Steg 6: Kontrollera att fullständig sidheap är aktiverad

Följande kommando visar de program som sid heap-verifiering är aktiverad för:

gflags /p

Som svar visar GFlags följande lista över program. I denna visning anger spårningar standardverifiering av sidheap, och fullständiga spårningar anger fullständig sidheapverifiering. I det här fallet visas pheap-buggy.exe med fullständiga spårningar, vilket indikerar att fullständig sid heap-verifiering är aktiverad, som avsett.

pheap-buggy.exe: page heap enabled with flags (full traces )

Steg 7: Kör felsökningsprogrammet igen

Följande kommando kör funktionen CorruptAfterEnd för pheap-buggy.exe i NTSD-felsökningsprogrammet med parametrarna -g (ignorera inledande brytpunkt) och -x (ange andra chansens avbrott i undantag för åtkomstöverträdelser):

ntsd -g -x pheap-buggy CorruptAfterEnd

När programmet misslyckas genererar NTSD följande visning, vilket indikerar att det upptäckte ett fel i pheap-buggy.exe:

Page heap: process 0x5BC created heap @ 00880000 (00980000, flags 0x3)
ModLoad: 77db0000 77e8c000   kernel32.dll
ModLoad: 78000000 78046000   MSVCRT.dll
Page heap: process 0x5BC created heap @ 00B60000 (00C60000, flags 0x3)
Page heap: process 0x5BC created heap @ 00C80000 (00D80000, flags 0x3)
Access violation - code c0000005 (first chance)
Access violation - code c0000005 (!!! second chance !!!)
eax=00c86f00 ebx=00000000 ecx=77fbd80f edx=00c85000 esi=00c80000 edi=00c16fd0
eip=01001398 esp=0006ff2c ebp=0006ff4c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000206
pheap-buggy!TestCorruptAfterEnd+1f:
01001398 889801010000     mov     [eax+0x101],bl          ds:0023:00c87001=??

När heapverifieringen för hela sidan är aktiverad bryts felsökningsprogrammet vid en åtkomstöverträdelse. Om du vill hitta den exakta platsen för åtkomstöverträdelsen aktiverar du radnummerdumpning och visar spårningen av anropsstacken.

Spårningen av den numrerade anropsstacken visas på följande sätt:

ChildEBP RetAddr  Args to Child
0006ff3c 01001450 00000000 00000001 0006ffc0 pheap-buggy!TestCorruptAfterEnd+0x1f [d:\nttest\base\testsrc\kernel\rtl\pageheap\pheap-buggy.cxx @ 184]
0006ff4c 0100157f 00000002 00c16fd0 00b70eb0 pheap-buggy!main+0xa9 [d:\nttest\base\testsrc\kernel\rtl\pageheap\pheap-buggy.cxx @ 69]
0006ffc0 77de43fe 00000000 00000001 7ffdf000 pheap-buggy!mainCRTStartup+0xe3 [crtexe.c @ 349]
WARNING: Stack unwind information not available. Following frames may be wrong.
0006fff0 00000000 0100149c 00000000 78746341 kernel32!DosPathToSessionPathA+0x204

Stackspårningen visar att problemet uppstår på rad 184 i pheap-buggy.exe. Eftersom helsides heap-verifiering är aktiverad startar anropsstacken i programkoden, inte i en system-dll. Som en följd upptäcktes regelbrottet där det hände, snarare än när heapblocket frigavs.

Steg 8: Hitta felet i koden

En snabb inspektion visar orsaken till problemet: Programmet försöker skriva till den 257:e byte (0x101) för en buffert på 256 byte (0x100), ett vanligt fel av typen off-by-one.

*((PCHAR)Block + 0x100) = 0;