Application Verifier – Debuggen der Anwendungsüberprüfung wird beendet
Debuggerinstallation und -einrichtung
Einige Application Verifier-Aktionen können dazu führen, dass eine Ausnahme ausgelöst wird. Der Debugger muss so festgelegt werden, dass er diese Ausnahmen bei der zweiten Chance abfangen kann, da die Anwendungsüberprüfung selbst die Ausnahmen für die erste Chance behandelt.
Die ausgelösten Ausnahmen haben drei Typen:
Eine Zugriffsverletzungsausnahme (0xC0000005) wird generiert, wenn die Heapoption einen Heappufferüberlauf erkennt. In einigen Fällen kann die Option Systempfadnutzung überprüfen auch zu einer Zugriffsverletzung führen.
Eine Ausnahme mit ungültigem Handle (0xC0000008) wird generiert, wenn die Option Verwendung ungültiger Handle erkennen einen ungültigen Handle-Vorgang erkennt.
Eine Stapelüberlaufausnahme (0xC00000FD) wird generiert, wenn die Option Nach geeignetem Stapel suchen erkennt, dass der anfängliche Stapel zu kurz war.
Eine Möglichkeit, sich auf diese Ereignisse vorzubereiten, besteht darin, den Debugger wie folgt über eine Befehlszeile zu starten:
windbg -xd av -xd ch -xd sov ApplicationCommandLine
oder
cdb -xd av -xd ch -xd sov ApplicationCommandLine
Wenn Sie den Debugger bereits gestartet haben, können Sie den Befehl sxd (Ausnahmen festlegen) verwenden, um alle Zugriffsverletzungen, ungültigen Handles und Stapelüberläufe als Ausnahmen für die zweite Chance abzufangen:
0:000> sxd av
0:000> sxd ch
0:000> sxd sov 1
Es ist theoretisch möglich, die Application Verifier über einen Kerneldebugger zu steuern. Dies wird jedoch nicht empfohlen. Dies erfordert häufig die Verwendung der Befehle .process und .pagein, aber es bietet Ihnen nicht mehr Leistung als die Verwendung eines Benutzermodusdebuggers.
Installieren der Debugtools
Informationen zum Herunterladen der neuesten Version der Tools finden Sie unter Herunterladen von Debugtools für Windows.
Konfigurieren von Hardware für User-Mode Debuggen
Das Debuggen im Benutzermodus erfolgt in der Regel auf einem einzelnen Computer: Der Debugger wird auf demselben Computer wie die fehlerhafte Anwendung ausgeführt.
In diesem Fall ist keine spezifische Hardwareeinrichtung erforderlich. In diesem Thema sind die Begriffe Hostcomputer und Zielcomputer in diesem Fall austauschbar.
Konfigurieren von Software für User-Mode Debugging
Grundlegende User-Mode Konfiguration: Bevor Sie mit dem Debuggen im Benutzermodus beginnen können, müssen Sie die erforderlichen Symboldateien herunterladen und bestimmte Umgebungsvariablen festlegen.
Symboldateien
Sie müssen die Symboldateien für den Benutzermodusprozess herunterladen, der gerade gedebuggt wird. Wenn es sich um eine von Ihnen geschriebene Anwendung handelt, sollte sie mit vollständigen Symboldateien erstellt werden. Wenn es sich um eine kommerzielle Anwendung handelt, können die Symboldateien auf einem Webserver oder zum Download verfügbar sein. Wenden Sie sich an den Hersteller.
Wenn Sie das Remotedebuggen ausführen, hängt der Speicherort der Symboldatei von der verwendeten Methode ab:
Wenn Sie das Remotedebuggen über den Debugger ausführen, sollten sich die Symboldateien auf dem Computer mit dem Debugserver befinden.
Wenn Sie das Remotedebuggen über remote.exe ausführen, sollten sich die Symboldateien auf dem Computer mit dem Debugger befinden.
Wenn Sie das Remotedebuggen über einen Prozessserver oder einen KD-Verbindungsserver durchführen, sollten sich die Symboldateien auf einem Computer mit dem smarten Client befinden.
Wenn Sie den Benutzermodusdebugger über den Kerneldebugger steuern, müssen sich die Symboldateien auf beiden Computern befinden.
Konfigurieren von Umgebungsvariablen
Der Debugger verwendet eine Vielzahl von Umgebungsvariablen, um eine Reihe wichtiger Einstellungen anzugeben.
Weitere Informationen zu Debuggern finden Sie unter Erste Schritte mit Windows-Debugging.
Konfigurieren der Application Verifier mit dem Debugger über die Befehlszeile
Zum Konfigurieren von Application Verifier können Sie die CDB- oder NTSD-Befehlszeile verwenden.
Verwenden Sie die folgende Befehlszeile:
cdb OtherOptions -vf:Flags Target
Dabei ist Target der Name der Zielanwendung und Flags gibt die gewünschten Optionen für die Anwendungsüberprüfung an, die auf dieses Ziel angewendet werden sollen.
Flags sollten eine Summe der Bits sein, die die gewünschten Optionen darstellen. Die einzelnen Bitwerte sind wie folgt:
Flagwert | Bedeutung |
---|---|
00000001 | HEAP-ÜBERPRÜFUNGEN |
00000004 | BEHANDELN VON ÜBERPRÜFUNGEN |
00000008 | SIM-ÜBERPRÜFUNGEN MIT GERINGEN RESSOURCEN |
00000020 | TLS-ÜBERPRÜFUNGEN |
00000040 | DIRTY STACKS |
00000200 | GEFÄHRLICHE APIS |
00001000 | AUSNAHMEPRÜFUNGEN |
00002000 | SPEICHERÜBERPRÜFUNGEN |
00020000 | VERSCHIEDENE ÜBERPRÜFUNGEN |
00040000 | SPERRÜBERPRÜFUNGEN |
Debuggen mit !avrf
Die Erweiterung !avrf steuert die Einstellungen von Application Verifier und zeigt eine Vielzahl von Ausgaben an, die von Application Verifier erzeugt werden. Weitere Informationen zur Erweiterung !arvrf finden Sie unter !avrf in der Debuggerdokumentation.
Syntax
!avrf
Der Befehl !avrf ohne Parameter zeigt die Anwendungsüberprüfungseinstellungen und Informationen zu den aktuellen und vorherigen Application Verifier-Unterbrechungen an, falls vorhanden.
!avrf –vs { Length | -aAddress }
Zeigt das Vorgangsprotokoll des virtuellen Raums an. Length gibt die Anzahl der Datensätze an, die ab dem letzten angezeigt werden sollen. Address gibt die virtuelle Adresse an. Datensätze der virtuellen Vorgänge, die diese virtuelle Adresse enthalten, werden angezeigt.
!avrf -hp { Length | -a Address }
Zeigt das Heapvorgangsprotokoll an. Address gibt die Heapadresse an. Datensätze der Heapvorgänge, die diese Heapadresse enthalten, werden angezeigt.
!avrf -cs { Length | -a Address }
Zeigt das Löschprotokoll des kritischen Abschnitts an. Length gibt die Anzahl der Datensätze an, die ab dem letzten angezeigt werden sollen. Address gibt die Adresse des kritischen Abschnitts an. Datensätze für den bestimmten kritischen Abschnitt werden angezeigt, wenn Adresse angegeben wird.
!avrf -dlls [ Length ]
Zeigt das DLL-Lade-/Entladeprotokoll an. Length gibt die Anzahl der Datensätze an, die ab dem letzten angezeigt werden sollen.
!avrf -trm
Zeigt ein Protokoll aller beendeten und angehaltenen Threads an.
!avrf -ex [ Length ]
Zeigt das Ausnahmeprotokoll an. Application Verifier verfolgt alle Ausnahmen, die in der Anwendung auftreten.
!avrf -threads [ ThreadID ]
Zeigt Informationen zu Threads im Zielprozess an. Für untergeordnete Threads werden auch die Stapelgröße und die vom übergeordneten Element angegebenen CreateThread-Flags angezeigt. Wenn Sie eine Thread-ID angeben, werden nur Informationen für diesen bestimmten Thread angezeigt.
!avrf -tp [ ThreadID ]
Zeigt das Threadpoolprotokoll an. Dieses Protokoll kann Stapelüberwachungen für verschiedene Vorgänge enthalten, z. B. das Ändern der Threadaffinitätsmaske, das Ändern der Threadpriorität, das Posten von Threadnachrichten, das Initialisieren von COM und das Aufheben der Initialisierung von COM innerhalb des Threadpoolrückrufs. Wenn Sie eine Thread-ID angeben, werden nur Informationen für diesen bestimmten Thread angezeigt.
!avrf -srw [ Address | Address Length ] [ -stats ]
Zeigt das SRW-Protokoll (Slim Reader/Writer) an. Wenn Sie Adresse angeben, werden Datensätze angezeigt, die sich auf diese SRW-Sperradresse beziehen. Wenn Länge zusammen mit der Adresse angegeben wird, werden alle SRW-Sperren innerhalb dieses Adressbereichs angezeigt. Die Option -stats gibt die SRW-Sperrstatistiken ab.
!avrf -leak [ -m ModuleName ] [ -r ResourceType ] [ -a Address ] [ -t ]
Zeigt das Ausstehende Ressourcenprotokoll an. Diese Ressourcen können zu einem bestimmten Zeitpunkt Lecks sein oder auch nicht. Wenn Sie ModuleName (einschließlich der Erweiterung) angeben, werden alle ausstehenden Ressourcen im angegebenen Modul angezeigt. Wenn Sie ResourceType angeben, werden ausstehende Ressourcen des jeweiligen Ressourcentyps angezeigt. Das Angeben von Adressabbildern enthält Datensätze ausstehender Ressourcen mit dieser Adresse. ResourceType kann eine der folgenden Elemente sein:
- Heap: Zeigt Heapzuordnungen mithilfe von Win32-Heap-APIs an
- Lokal: Zeigt lokale/globale Zuordnungen an
- CRT: Zeigt Zuordnungen mithilfe von CRT-APIs an
- Virtual: Zeigt virtuelle Reservierungen an
- BSTR: Zeigt BSTR-Zuordnungen an
- Registrierung: Zeigt registrierungsschlüssel geöffnet an
- Power: Zeigt Energiebenachrichtigungsobjekte an
- Handle: Zeigt Thread-, Datei- und Ereignishandlezuordnungen an
!avrf –trace TraceIndex
Zeigt eine Stapelablaufverfolgung für den angegebenen Ablaufverfolgungsindex an. Einige Strukturen verwenden diese 16-Bit-Indexnummer, um eine Stapelablaufverfolgung zu identifizieren. Dieser Index verweist auf einen Speicherort in der Stapelablaufverfolgungsdatenbank. Wenn Sie eine solche Struktur analysieren, finden Sie diese Syntax nützlich.
!avrf -cnt
Zeigt eine Liste globaler Leistungsindikatoren an.
!avrf -brk [ BreakEventType ]
Gibt an, dass es sich um einen Break-Event-Befehl handelt. Wenn !avrf -brk
keine zusätzlichen Parameter verwendet werden, werden die Einstellungen für das Unterbrechungsereignis angezeigt. BreakEventType gibt die Typnummer des Umbruchereignisses an. Verwenden Sie !avrf -brk
für eine Liste der möglichen Typen .
!avrf -flt [ EventTypeProbability ]
Gibt an, dass es sich um einen Fehlereinschleusungsbefehl handelt. Wenn !avrf -flt
ohne zusätzliche Parameter verwendet wird, werden die aktuellen Fehlereinschleusungseinstellungen angezeigt. EventType gibt die Typnummer des Ereignisses an. Wahrscheinlichkeit gibt die Häufigkeit an, mit der das Ereignis fehlschlägt. Dies kann eine beliebige ganze Zahl zwischen 0 und 1.000.000 (0xF4240) sein.
!avrf -flt break EventType
Bewirkt, dass die Anwendungsüberprüfung jedes Mal in den Debugger einbricht, wenn dieser Fehler eingefügt wird.
!avrf -flt stacks Length
Zeigt die Längenanzahl der Stapelablaufverfolgungen für die zuletzt fehlerinjizierten Vorgänge an.
!avrf -trg [ StartEnd | dll Module | all ]
Gibt an, dass es sich um einen Zielbereichsbefehl handelt. Wenn -trg ohne zusätzliche Parameter verwendet wird, werden die aktuellen Zielbereiche angezeigt. Start gibt die Anfangsadresse des Ziel- oder Ausschlussbereichs an. End gibt die Endadresse des Ziel- oder Ausschlussbereichs an. Module gibt den Namen eines Moduls an, das als Ziel oder ausgeschlossen werden soll. Das Modul sollte den vollständigen Modulnamen enthalten, einschließlich der .exe- oder .dll-Erweiterung. Pfadinformationen sollten nicht enthalten sein. Wenn Sie alle angeben, werden alle Zielbereiche oder Ausschlussbereiche zurückgesetzt.
!avrf -skp [ StartEnd | dll Module | all | Time ]
Gibt an, dass es sich um einen Ausschlussbereichsbefehl handelt. Start gibt die Anfangsadresse des Ziel- oder Ausschlussbereichs an. End gibt die Endadresse des Ziel- oder Ausschlussbereichs an. Module gibt den Namen eines Moduls an, das als Ziel oder ausgeschlossen werden soll. Das Modul sollte den vollständigen Modulnamen enthalten, einschließlich der .exe- oder .dll-Erweiterung. Pfadinformationen sollten nicht enthalten sein. Wenn Sie alle angeben, werden alle Zielbereiche oder Ausschlussbereiche zurückgesetzt. Die Angabe von Time bewirkt, dass alle Fehler für Zeit-Millisekunden unterdrückt werden, nachdem die Ausführung fortgesetzt wurde.
Im Folgenden finden Sie die Ausgabe, die vom Befehl !avrf im Debugger bereitgestellt wird.
0:000> !avrf
Application verifier settings (816431A7):
- full page heap
- COM
- RPC
- Handles
- Locks
- Memory
- TLS
- Exceptions
- Threadpool
- Leak
- SRWLock
No verifier stop active.
Note: Sometimes bugs found by verifier manifest themselves as raised
exceptions (access violations, stack overflows, invalid handles),
and it is not always necessary to have a verifier stop.
Kommentare der !avrf-Erweiterung
Wenn die Erweiterung !avrf ohne Parameter verwendet wird, werden die aktuellen Optionen für die Anwendungsüberprüfung angezeigt.
Die Erweiterung !avrf verwendet die Exts.dll im Debugger.
Wenn ein Application Verifier-Stopp aufgetreten ist, zeigt die !avrf-Erweiterung ohne Parameter die Art des Stopps und die Ursache an.
Wenn Symbole für ntdll.dll und verifier.dll fehlen, generiert die Erweiterung !avrf eine Fehlermeldung.
Fortlaufende und nicht fortsetzbare Stopps
Debuggen eines fortlaufenden Stopps
Hier sehen Sie ein Beispiel für eine ungültige Handle-Ausnahme, die von der Option Ungültige Handlenutzung erkennen ausgelöst wurde.
Zunächst wird die folgende Meldung angezeigt:
Invalid handle - code c0000008 (first chance)
===================================================
VERIFIER STOP 00000300: pid 0x558: invalid handle exception for current stack trace
C0000008 : Exception code.
0012FBF8 : Exception record. Use .exr to display it.
0012FC0C : Context record. Use .cxr to display it.
00000000 :
===================================================
This verifier stop is continuable.
After debugging it use 'go' to continue.
===================================================
Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=6a27c280 ecx=6a226447 edx=0012fa4c esi=00942528 edi=6a27c260
eip=6a22629c esp=0012facc ebp=0012faf0 iopl=0 nv up ei pl zr na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!DbgBreakPoint:
6a22629c cc int 3
Beachten Sie, dass Sie in der Meldung erfahren, dass dieser Application Verifier-Stopp fortgesetzt werden kann. Nachdem Sie verstanden haben, was sich herausgestellt hat, können Sie die Zielanwendung weiter ausführen.
Zunächst sollten Sie die Erweiterung !avrf verwenden. Dadurch erhalten Sie Informationen zum aktuellen Fehler:
0:000> !avrf
Global flags: 00000100
Application verifier global flag is set.
Application verifier settings (00000004):
- no heap checking enabled!
- handle checks
Page heap is not active for this process.
Current stop 00000300 : c0000008 0012fbf8 0012fc0c 00000000 .
Using an invalid handle (either closed or simply bad).
In der letzten Zeile dieser Anzeige wird das Problem zusammengefasst.
Möglicherweise sollten Sie sich an dieser Stelle einige Protokolle ansehen. Nachdem Sie fertig sind, verwenden Sie den Befehl g (Go), um die Anwendung erneut zu starten:
0:000> g
## Debugging a Non-Continuable Stop
Here is an example of an access violation that has been raised by the page heap option.
First, the following message appears:
Access violation - code c0000005 (first chance)
===================================================
VERIFIER STOP 00000008: pid 0x504: exception raised while verifying block header
00EC1000 : Heap handle
00F10FF8 : Heap block
00000000 : Block size
00000000 :
===================================================
This verifier stop is not continuable. Process will be terminated when you use the 'go' debugger command.
===================================================
Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=6a226447 edx=0012fab7 esi=00f10ff8 edi=00000008
eip=6a22629c esp=0012fb5c ebp=0012fb80 iopl=0 nv up ei pl zr na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!DbgBreakPoint:
6a22629c cc int 3
In diesem Fall wird Ihnen in der Meldung mitgeteilt, dass dieser Anwendungsüberprüfungsstopp nicht fortgesetzt werden kann. Der Fehler ist zu schwerwiegend, damit der Prozess weiter ausgeführt werden kann, und es gibt keine Möglichkeit für Application Verifier, den Prozess zu retten.
Die Erweiterung !avrf kann verwendet werden, um Informationen zum aktuellen Fehler zu geben:
0:000> !avrf
Global flags: 02000100
Application verifier global flag is set.
Page heap global flag is set.
Application verifier settings (00000001):
- full page heap
Page heaps active in the process (format: pageheap, lightheap, flags):
00941000 , 00a40000 , 3 (pageheap traces )
00b41000 , 00c40000 , 3 (pageheap traces )
00cb1000 , 00db0000 , 3 (pageheap traces )
00ec1000 , 00fc0000 , 3 (pageheap traces )
Current stop 00000008 : 00ec1000 00f10ff8 00000000 00000000 .
Corrupted heap block.
In der letzten Zeile dieser Anzeige wird das Problem zusammengefasst.
Möglicherweise sollten Sie sich an dieser Stelle auch einige Protokolle ansehen. Sie können an diesem Punkt den Befehl NEUSTART (Zielanwendung neu starten) verwenden. Oder vielleicht bevorzugen Sie es, Ihre Application Verifier-Sitzung zu beenden und mit der Behebung der Fehler in Ihrem Code zu beginnen.
Debuggen kritischer Abschnittsfehler
!cs-Debuggererweiterung
!cs kann sowohl im Benutzermodusdebugger als auch im Kerneldebugger verwendet werden, um Informationen zu wichtigen Abschnitten im aktuellen Prozess anzuzeigen. Weitere Informationen zur Erweiterung !cs finden Sie unter !cs in der Debuggerdokumentation.
Der Abgleich von Symbolen mit Typinformationen ist insbesondere für ntdll.dll erforderlich.
Die Syntax für diese Erweiterung lautet:
!cs [-s] – Führen Sie alle aktiven kritischen Abschnitte im aktuellen Prozess aus.
!cs [-s] address: Enthält einen kritischen Abschnitt an dieser Adresse.
!cs [-s] -d address : Dumpkritisch, der DebugInfo an dieser Adresse entspricht.
-s gibt die Stapelablaufverfolgung des kritischen Abschnitts ab, wenn sie verfügbar ist.
Beispiele:
Informationen zu einem kritischen Abschnitt mithilfe seiner Adresse abspeichern
0:001> ! cs 0x7803B0F8
Critical section = 0x7803B0F8 (MSVCRT!__app_type+0x4)
DebugInfo = 0x6A262080
NOT LOCKED
LockSemaphore = 0x0
SpinCount = 0x0
Abspeichern von Informationen zu einem kritischen Abschnitt mithilfe seiner Adresse, einschließlich Der Ablaufverfolgung des Initialisierungsstapels
0:001> !cs -s 0x7803B0F8
Critical section = 0x7803B0F8 (MSVCRT!__app_type+0x4)
DebugInfo = 0x6A262080
NOT LOCKED
LockSemaphore = 0x0
SpinCount = 0x0
Stack trace for DebugInfo = 0x6A262080:
0x6A2137BD: ntdll!RtlInitializeCriticalSectionAndSpinCount+0x9B
0x6A207A4C: ntdll!LdrpCallInitRoutine+0x14
0x6A205569: ntdll!LdrpRunInitializeRoutines+0x1D9
0x6A20DCE1: ntdll!LdrpInitializeProcess+0xAE5
Abspeichern von Informationen zu einem kritischen Abschnitt mithilfe seiner Debuginformationsadresse
0:001> !cs -d 0x6A262080
DebugInfo = 0x6A262080
Critical section = 0x7803B0F8 (MSVCRT!__app_type+0x4)
NOT LOCKED
LockSemaphore = 0x0
SpinCount = 0x0
Abspeichern von Informationen zu einem kritischen Abschnitt mithilfe seiner Debuginformationsadresse, einschließlich Der Ablaufverfolgung des Initialisierungsstapels
0:001> !cs -s -d 0x6A262080
DebugInfo = 0x6A262080
Critical section = 0x7803B0F8 (MSVCRT!__app_type+0x4)
NOT LOCKED
LockSemaphore = 0x0
SpinCount = 0x0
Stack trace for DebugInfo = 0x6A262080:
0x6A2137BD: ntdll!RtlInitializeCriticalSectionAndSpinCount+0x9B
0x6A207A4C: ntdll!LdrpCallInitRoutine+0x14
0x6A205569: ntdll!LdrpRunInitializeRoutines+0x1D9
0x6A20DCE1: ntdll!LdrpInitializeProcess+0xAE
Informationen zu allen aktiven kritischen Abschnitten im aktuellen Prozess abspeichern
0:001> !cs
-----------------------------------------
DebugInfo = 0x6A261D60
Critical section = 0x6A262820 (ntdll!RtlCriticalSectionLock+0x0)
LOCKED
LockCount = 0x0
OwningThread = 0x460
RecursionCount = 0x1
LockSemaphore = 0x0
SpinCount = 0x0
-----------------------------------------
DebugInfo = 0x6A261D80
Critical section = 0x6A262580 (ntdll!DeferedCriticalSection+0x0)
NOT LOCKED
LockSemaphore = 0x7FC
SpinCount = 0x0
-----------------------------------------
DebugInfo = 0x6A262600
Critical section = 0x6A26074C (ntdll!LoaderLock+0x0)
NOT LOCKED
LockSemaphore = 0x0
SpinCount = 0x0
.....
Abspeichern von Informationen zu allen aktiven kritischen Abschnitten im aktuellen Prozess, einschließlich Der Ablaufverfolgung des Initialisierungsstapels
0:001> !cs -s
...
-----------------------------------------
DebugInfo = 0x6A261EA0
Critical section = 0xA8001C (+0xA8001C)
NOT LOCKED
LockSemaphore = 0x0
SpinCount = 0x0
No stack trace saved
-----------------------------------------
DebugInfo = 0x6A261EC0
Critical section = 0x6A263560 (ntdll!RtlpDphTargetDllsLock+0x0)
NOT LOCKED
LockSemaphore = 0x0
SpinCount = 0x0
No stack trace saved
-----------------------------------------
DebugInfo = 0x6A261EE0
Critical section = 0xA90608 (+0xA90608)
NOT LOCKED
LockSemaphore = 0x7EC
SpinCount = 0x0
Stack trace for DebugInfo = 0x6A261EE0:
0x6A2137BD: ntdll!RtlInitializeCriticalSectionAndSpinCount+0x9B
0x6A20B0DC: ntdll!CsrpConnectToServer+0x1BE
0x6A20B2AA: ntdll!CsrClientConnectToServer+0x148
0x77DBE83F: KERNEL32!BaseDllInitialize+0x11F
0x6A207A4C: ntdll!LdrpCallInitRoutine+0x14
0x6A205569: ntdll!LdrpRunInitializeRoutines+0x1D9
0x6A20DCE1: ntdll!LdrpInitializeProcess+0xAE5
-----------------------------------------
DebugInfo = 0x6A261F00
Critical section = 0x77E1AEB8 (KERNEL32!BaseDllRegistryCache+0x18)
NOT LOCKED
LockSemaphore = 0x0
SpinCount = 0x0
Stack trace for DebugInfo = 0x6A261F00:
0x6A2137BD: ntdll!RtlInitializeCriticalSectionAndSpinCount+0x9B
0x6A207A4C: ntdll!LdrpCallInitRoutine+0x14
0x6A205569: ntdll!LdrpRunInitializeRoutines+0x1D9
0x6A20DCE1: ntdll!LdrpInitializeProcess+0xAE5
Debuggen von Ausnahmefehlern
Das Ausnahmeprotokoll zeichnet alle Ausnahmen auf, die im Zielprozess aufgetreten sind.
Sie können den Erweiterungsbefehl !avrf -ex Length verwenden, um die letzten Ausnahmen anzuzeigen. Length gibt die Anzahl der Ausnahmen an. Wenn Length ausgelassen wird, werden alle Ausnahmen angezeigt.
Beispiel:
0:000> !avrf -ex 4
=================================
Thread ID: 0000052c
Exception code: c0000008
Exception address: 6a226663
Exception record: 0012fb50
Context record: 0012fb64
Displayed 1 exception log entries.
Debuggen behandelt Fehler
!htrace kann sowohl im Benutzermodusdebugger als auch im Kerneldebugger verwendet werden, um Stapelablaufverfolgungsinformationen für einen oder alle Handles in einem Prozess anzuzeigen. Diese Informationen sind verfügbar, wenn die Handle-Ablaufverfolgung für den Prozess aktiviert ist – automatisch aktiviert, wenn die Handle-Überprüfung in der Anwendungsüberprüfung aktiviert ist. Stapelablaufverfolgungen werden jedes Mal gespeichert, wenn der Prozess ein Handle öffnet oder schließt oder wenn er auf ein ungültiges Handle verweist. Weitere Informationen zur Erweiterung !htrace finden Sie in der Debuggerdokumentation unter !htrace .
Die Kerneldebuggersyntax für diese Erweiterung lautet:
!htrace [ handle [process] ]
Wenn handle nicht angegeben oder 0 ist, werden Informationen zu allen Handles im Prozess angezeigt. Wenn der Prozess nicht angegeben ist, wird der aktuelle Prozess verwendet.
Die Syntax des Benutzermodusdebuggers lautet:
!htrace [handle]
Die Benutzermodusdebuggererweiterung zeigt immer Informationen zum aktuellen Debugprozess an.
Beispiele:
Speicherabbildinformationen zu Handle 7CC in Prozess 815328b0
kd> !htrace 7CC 815328b0
Loaded \\...\kdexts extension DLL
Process 0x815328B0
ObjectTable 0xE15ECBB8
--------------------------------------
Handle 0x7CC - CLOSE:
0x8018FCB9: ntoskrnl!ExDestroyHandle+0x103
0x801E1D12: ntoskrnl!ObpCloseHandleTableEntry+0xE4
0x801E1DD9: ntoskrnl!ObpCloseHandle+0x85
0x801E1EDD: ntoskrnl!NtClose+0x19
0x77DBFCD6: KERNEL32!GetLocaleFileInfo+0x3D
0x77DBF942: KERNEL32!NlsProcessInitialize+0x11D
0x77E0C6DF: KERNEL32!NlsDllInitialize+0x35
0x6A20785C: ntdll!LdrpCallInitRoutine+0x14
0x6A205393: ntdll!LdrpRunInitializeRoutines+0x1D9
0x6A20DD80: ntdll!LdrpInitializeProcess+0xAF6
--------------------------------------
Handle 0x7CC - OPEN:
0x8018F44A: ntoskrnl!ExCreateHandle+0x94
0x801E3180: ntoskrnl!ObpCreateHandle+0x304
0x801E1563: ntoskrnl!ObOpenObjectByName+0x1E9
0x77DBFCD6: KERNEL32!GetLocaleFileInfo+0x3D
0x77DBF942: KERNEL32!NlsProcessInitialize+0x11D
0x77E0C6DF: KERNEL32!NlsDllInitialize+0x35
0x6A20785C: ntdll!LdrpCallInitRoutine+0x14
0x6A205393: ntdll!LdrpRunInitializeRoutines+0x1D9
0x6A20DD80: ntdll!LdrpInitializeProcess+0xAF6
--------------------------------------
Parsed 0x1CA stack traces.
Dumped 0x2 stack traces.
Speicherabbildinformationen zu allen Handles in Prozess 815328b0
kd> !htrace 0 81400300
Process 0x81400300
ObjectTable 0xE10CCF60
--------------------------------------
Handle 0x7CC - CLOSE:
0x8018FCB9: ntoskrnl!ExDestroyHandle+0x103
0x801E1D12: ntoskrnl!ObpCloseHandleTableEntry+0xE4
0x801E1DD9: ntoskrnl!ObpCloseHandle+0x85
0x801E1EDD: ntoskrnl!NtClose+0x19
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Handle 0x7CC - OPEN:
0x8018F44A: ntoskrnl!ExCreateHandle+0x94
0x801E3390: ntoskrnl!ObpCreateUnnamedHandle+0x10C
0x801E7317: ntoskrnl!ObInsertObject+0xC3
0x77DE23B2: KERNEL32!CreateSemaphoreA+0x66
0x010011C5: badhandle!main+0x45
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Handle 0x7DC - BAD REFERENCE:
0x8018F709: ntoskrnl!ExMapHandleToPointerEx+0xEA
0x801E10F2: ntoskrnl!ObReferenceObjectByHandle+0x12C
0x801902BE: ntoskrnl!NtSetEvent+0x6C
0x80154965: ntoskrnl!_KiSystemService+0xC4
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Handle 0x7DC - CLOSE:
0x8018FCB9: ntoskrnl!ExDestroyHandle+0x103
0x801E1D12: ntoskrnl!ObpCloseHandleTableEntry+0xE4
0x801E1DD9: ntoskrnl!ObpCloseHandle+0x85
0x801E1EDD: ntoskrnl!NtClose+0x19
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Handle 0x7DC - OPEN:
0x8018F44A: ntoskrnl!ExCreateHandle+0x94
0x801E3390: ntoskrnl!ObpCreateUnnamedHandle+0x10C
0x801E7317: ntoskrnl!ObInsertObject+0xC3
0x77DE265C: KERNEL32!CreateEventA+0x66
0x010011A0: badhandle!main+0x20
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Parsed 0x6 stack traces.
Dumped 0x5 stack traces.
Speicherabbildinformationen zum Handle 7DC im aktuellen Prozess
kd> !htrace 7DC
Process 0x81400300
ObjectTable 0xE10CCF60
--------------------------------------
Handle 0x7DC - BAD REFERENCE:
0x8018F709: ntoskrnl!ExMapHandleToPointerEx+0xEA
0x801E10F2: ntoskrnl!ObReferenceObjectByHandle+0x12C
0x801902BE: ntoskrnl!NtSetEvent+0x6C
0x80154965: ntoskrnl!_KiSystemService+0xC4
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Handle 0x7DC - CLOSE:
0x8018FCB9: ntoskrnl!ExDestroyHandle+0x103
0x801E1D12: ntoskrnl!ObpCloseHandleTableEntry+0xE4
0x801E1DD9: ntoskrnl!ObpCloseHandle+0x85
0x801E1EDD: ntoskrnl!NtClose+0x19
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Handle 0x7DC - OPEN:
0x8018F44A: ntoskrnl!ExCreateHandle+0x94
0x801E3390: ntoskrnl!ObpCreateUnnamedHandle+0x10C
0x801E7317: ntoskrnl!ObInsertObject+0xC3
0x77DE265C: KERNEL32!CreateEventA+0x66
0x010011A0: badhandle!main+0x20
0x010012C1: badhandle!mainCRTStartup+0xE3
0x77DE0B2F: KERNEL32!BaseProcessStart+0x3D
--------------------------------------
Parsed 0x6 stack traces.
Dumped 0x3 stack traces.
Debuggen von Heapfehlern
Debuggererweiterung für die Heapüberprüfung
Die Debuggererweiterung für die Heapüberprüfung ist Teil der Erweiterung !heap (NT-Heapdebuggererweiterung). Einfache Hilfe erhalten Sie mit !heap -? oder umfangreicher mit !heap -p -? . Die aktuelle Erweiterung erkennt nicht selbst, ob seitenheap für einen Prozess aktiviert ist, und handelt entsprechend. Vorerst muss der Benutzer der Erweiterung wissen, dass der Seitenheap aktiviert ist, und Befehle verwenden, die mit dem Präfix !heap -p versehen sind. Weitere Informationen zur !htrace-Erweiterung finden Sie unter !heap in der Debuggerdokumentation.
!heap -p
Speicherabbilder aller ganzseitigen Heaps, die im Prozess erstellt wurden.
!heap -p -h ADDRESS-OF-HEAP
Vollständiges Abbild des Ganzseitenheaps unter ADDRESS-OF-HEAP.
!heap -p -a ADDRESS
Versucht herauszufinden, ob bei ADDRESS ein Heapblock vorhanden ist. Dieser Wert muss nicht die Adresse des Anfangs des Blocks sein. Der Befehl ist nützlich, wenn überhaupt kein Hinweis auf die Art eines Speicherbereichs vorhanden ist.
Heap-Vorgangsprotokoll
Im Heapvorgangsprotokoll werden alle Heaproutinen nachverfolgt. Dazu gehören HeapAlloc, HeapReAlloc und HeapFree.
Sie können den Erweiterungsbefehl !avrf -hp Length
verwenden, um die letzten Datensätze anzuzeigen. Length gibt die Anzahl der Datensätze an.
Sie können verwenden !avrf -hp -a Address
, um alle Heapspeicherplatzvorgänge anzuzeigen, die sich auf die angegebene Adresse auswirken. Für einen Zuordnungsvorgang reicht es aus, dass Address im zugeordneten Heapblock enthalten ist. Für einen freien Vorgang muss die genaue Adresse des Anfangs des Blocks angegeben werden.
Für jeden Eintrag im Protokoll werden die folgenden Informationen angezeigt:
- Die Heapfunktion wird aufgerufen.
- Die Thread-ID des Threads, der die Routine aufgerufen hat.
- Die Adresse, die am Anruf beteiligt ist– dies ist die Adresse, die von einer Zuordnungsroutine zurückgegeben oder an eine freie Routine übergeben wurde.
- Die Größe der am Anruf beteiligten Region.
- Die Stapelablaufverfolgung des Aufrufs.
Die neuesten Einträge werden zuerst angezeigt.
In diesem Beispiel werden die beiden letzten Einträge angezeigt:
0:001> !avrf -hp 2
alloc (tid: 0xFF4):
address: 00ea2fd0
size: 00001030
00403062: Prymes!_heap_alloc_dbg+0x1A2
00402e69: Prymes!_nh_malloc_dbg+0x19
00402e1e: Prymes!_malloc_dbg+0x1E
00404ff3: Prymes!_stbuf+0xC3
00401c23: Prymes!printf+0x43
00401109: Prymes!main+0xC9
00402039: Prymes!mainCRTStartup+0xE9
77e7a278: kernel32!BaseProcessStart+0x23
alloc (tid: 0xFF4):
address: 00ea07d0
size: 00000830
00403062: Prymes!_heap_alloc_dbg+0x1A2
00402e69: Prymes!_nh_malloc_dbg+0x19
00402e1e: Prymes!_malloc_dbg+0x1E
00403225: Prymes!_calloc_dbg+0x25
00401ad5: Prymes!__initstdio+0x45
00401f38: Prymes!_initterm+0x18
00401da1: Prymes!_cinit+0x21
00402014: Prymes!mainCRTStartup+0xC4
77e7a278: kernel32!BaseProcessStart+0x23
Typische Debugszenarien
Es gibt mehrere Fehlerszenarien, die auftreten können. Einige von ihnen erfordern einige detektivische Arbeit, um das ganze Bild zu bekommen.
Zugriffsverletzung auf nicht zugänglicher Seite
Dies geschieht, wenn der ganzseitige Heap aktiviert ist, wenn die getestete Anwendung über das Ende des Puffers zugreift. Es kann auch passieren, wenn es einen freigegebenen Block berührt. Um die Art der Adresse zu verstehen, für die die Ausnahme aufgetreten ist, müssen Sie Folgendes verwenden:
!heap –p –a ADDRESS-OF-AV
Beschädigte Blocknachricht
In mehreren Momenten während der Lebensdauer einer Zuordnung (Zuordnung, benutzerfrei, real kostenlos) überprüft der Seitenheap-Manager, ob der Block alle Füllmuster intakt hat und der Blockheader konsistente Daten enthält. Wenn dies nicht der Fall ist, erhalten Sie einen Prüferstopp.
Wenn der Block ein ganzseitiger Heapblock ist (wenn Sie z. B. wissen, dass der ganze Seitenheap für alle Zuordnungen aktiviert ist), können Sie "!heap –p –a ADDRESS" verwenden, um herauszufinden, welche Merkmale der Block aufweist.
Wenn es sich bei dem Block um einen hellen Seitenheapblock handelt, müssen Sie die Startadresse für den Blockheader ermitteln. Sie können die Startadresse finden, indem Sie 30-40 Bytes unter die gemeldete Adresse geben und nach den magischen Start/End-Mustern für einen Blockheader suchen (ABCDAAAA, ABCDBBBB, ABCDAAA9, ABCDBBBA).
Der Header enthält alle Informationen, die Sie benötigen, um den Fehler zu verstehen. Insbesondere zeigen die magischen Muster an, ob der Block zugeordnet oder frei ist, wenn es sich um einen hellen Seitenheap oder einen ganzseitigen Heapblock handelt. Die Informationen hier müssen sorgfältig mit dem beleidigenden Aufruf abgeglichen werden.
Wenn beispielsweise ein Aufruf von HeapFree mit der Adresse eines Blocks plus vier Bytes erfolgt, erhalten Sie die beschädigte Nachricht. Der Blockheader sieht in Ordnung aus, aber Sie müssen feststellen, dass das erste Byte nach dem Ende des Headers (erstes Byte nach dem Magic-Wert 0xDCBAXXXX) eine andere Adresse als die im Aufruf hat.
Spezielle Füllzeiger
Der Seitenheap-Manager füllt die Benutzerzuordnung mit Werten aus, die als Kernelzeiger aussehen. Dies geschieht, wenn der Block freigegeben wird (Füllwert ist F0) und wenn der Block zugeordnet wird, aber keine Anforderung für den Block auf Null gestellt wird (Füllwert ist E0 für den hellen Seitenheap und C0 für ganzseitigen Heap). Die Zuordnungen ohne Null sind typisch für malloc/new-Benutzer. Wenn es einen Fehler (Zugriffsverletzung) gibt, bei dem ein Lese-/Schreibversuch für Adressen wie F0F0F0F0, E0E0E0E0, C0C0C0C0 wird höchstwahrscheinlich einer dieser Fälle angezeigt.
Ein Lese-/Schreibzugriff bei F0F0F0F0 bedeutet, dass ein Block verwendet wurde, nachdem er freigegeben wurde. Leider benötigen Sie einige Detektivarbeit, um herauszufinden, welcher Block dies verursacht hat. Sie müssen die Stapelüberwachung des Fehlers abrufen und dann den Code auf die Funktionen im Stapel untersuchen. Einer von ihnen könnte eine falsche Annahme treffen, dass eine Zuordnung am Leben ist.
Ein Lese-/Schreibzugriff bei E0E0E0E0/C0C0C0C0 bedeutet, dass die Anwendung die Zuordnung nicht ordnungsgemäß initialisiert hat. Dies erfordert auch die Codeüberprüfung der Funktionen in der aktuellen Stapelüberwachung. Hier ist es ein Beispiel für diese Art von Fehler. In einem Testprozess wurde eine Zugriffsverletzung beim Ausführen eines HeapFree-E0E0E0E0 festgestellt. Es stellte sich heraus, dass der Test eine -Struktur zugeordnet, sie nicht ordnungsgemäß initialisiert und dann den Destruktor des Objekts aufgerufen hat. Da ein bestimmtes Feld nicht NULL war (es hatte E0E0E0E0 darin), hat es delete aufgerufen.
Technische Details zum Seitenheap
Um Heapbeschädigungen (Überläufe oder Unterläufe) zu erkennen, ändert AppVerifier die Speicherbelegung, indem der angeforderte Arbeitsspeicher entweder mit vollständigen nicht beschreibbaren Seiten oder mit speziellen Tags vor und nach dem zugeordneten Arbeitsspeicher aufgefüllt wird. Dazu lädt AppVerifier Verifier.dll in den überprüften Prozess und leitet einige der von der Anwendung aufgerufenen Win32-Heap-APIs an die entsprechenden Verifier.dll-APIs um.
Beim Auffüllen des angeforderten Arbeitsspeichers mit vollständigen nicht beschreibbaren Seiten (die Einstellung FULL ist im Abschnitt mit den Seitenheapeigenschaften aktiviert und ist die Standardeinstellung), verbraucht AppVerifier eine große Menge an virtuellem Arbeitsspeicher, hat jedoch den Vorteil, dass Heapbeschädigungsereignisse in Echtzeit zwischengespeichert werden, wenn der Überlauf oder Unterlauf auftritt. Denken Sie daran, dass der Arbeitsspeicher in diesem Modus entweder wie folgt aussieht [AppVerifier Read-Only Heap page (4k)] [Menge des von der zu test stehenden Anwendung angeforderten Arbeitsspeichers] oder wie folgt [Menge des von der getesteten Anwendung angeforderten Arbeitsspeichers] [AppVerifier Read-Only Heap page (4k)].
Bei der Heapprüfung wird eine Wächterseite am Anfang oder Ende der Zuordnung platziert, abhängig von der Backward-Eigenschaft. Wenn Rückwärts auf False festgelegt ist, was die Standardeinstellung ist, wird eine Schutzseite am Ende der Zuordnung platziert, um Pufferüberläufe abzufangen. Wenn sie auf True festgelegt ist, wird die Schutzseite am Anfang der Zuordnung platziert, um Pufferunterläufe abzufangen.
Beim Auffüllen des angeforderten Arbeitsspeichers mit speziellen Tags (aktiviert durch Deaktivieren des Kontrollkästchenelements "Vollständig" in den Heapeigenschaften), überprüft AppVerifier und benachrichtigt Sie, wenn dieser Speicher freigegeben wird. Das Standard Problem bei der Verwendung dieser Technik besteht darin, dass es einige Fälle gibt, in denen die Speicherbeschädigung erst erkannt wird, wenn der Arbeitsspeicher freigegeben wird (die Mindestmenge des Arbeitsspeicherblocks beträgt 8 Byte). Wenn also eine 3-Byte-Variable oder ein 5-Byte-Überlauf auftritt, wird er nicht sofort erkannt.
Bei einem Unterlaufereignis wird versucht, in eine Read-Only Seite zu schreiben. Dadurch wird eine Ausnahme ausgelöst. Beachten Sie, dass diese Ausnahme nur abgefangen werden kann, wenn die Zielanwendung unter einem Debugger ausgeführt wird. Beachten Sie, dass der Ganzseitenheapmodus diese Fehler ebenfalls erkennt, da er Auffüllen+Schützen von Seiten verwendet. Der Grund, warum Sie den hellen Seitenheap verwenden würden, ist, wenn Ihr Computer die hohen Speichereinschränkungen des Ganzseitenheaps nicht tolerieren kann.
Bei speicherintensiven Anwendungen oder wenn AppVerifier während langer Zeiträume (z. B. Belastungstests) verwendet werden muss, ist es aufgrund der Leistungsbeeinträchtigung besser, normale (leichte) Heaptests statt im Vollmodus auszuführen. Wenn jedoch ein Problem vorliegt, aktivieren Sie den ganzseitigen Heap, um dies weiter zu untersuchen.
Anwendungen, die benutzerdefinierte Heaps verwenden (ein Heap, der die Implementierung des Heaps des Betriebssystems umgeht), können möglicherweise nicht den vollen Vorteil der Verwendung von Seitenheaps nutzen oder sogar fehlfunktionieren, wenn er aktiviert ist.
Debuggen von Arbeitsspeicherfehlern
Die Speicherüberprüfungsdebuggererweiterung
Im Vorgangsprotokoll für virtuelle Räume werden alle Routinen nachverfolgt, die den virtuellen Bereich eines Prozesses in beliebiger Weise ändern. Dazu gehören VirtualAlloc, VirtualFree, MapViewOfFile und UnmapViewOfFile.
Sie können den Erweiterungsbefehl !avrf -vs Length
verwenden, um die letzten Datensätze anzuzeigen. Length gibt die Anzahl der Datensätze an.
Sie können !avrf -vs -a Address verwenden, um alle Vorgänge des virtuellen Raums anzuzeigen, die sich auf die angegebene Adresse auswirken. Für eine Zuordnung reicht es aus, dass Die Adresse im zugeordneten Block enthalten ist. Für einen kostenlosen muss die genaue Adresse des Anfangs der Region angegeben werden.
Für jeden Eintrag im Protokoll werden die folgenden Informationen angezeigt:
- Die -Funktion mit dem Namen
- Die Thread-ID des Threads, der die Routine aufgerufen hat.
- Die Adresse, die am Anruf beteiligt ist – dies ist die Adresse, die von einer Zuordnungsroutine zurückgegeben oder an eine freie Routine übergeben wurde.
- Die Größe der Region, die am Anruf beteiligt ist
- Der Typ des Arbeitsspeichervorgangs (der AllocationType-Parameter)
- Der Typ des angeforderten Schutzes
- Die Stapelüberwachung des Aufrufs
Beispiele
Die neuesten Einträge werden zuerst angezeigt.
Im folgenden Beispiel werden die beiden letzten Einträge angezeigt:
0:001> !avrf -vs 2
VirtualFree (tid: 0xB4): addr:04bb0000 sz:00400000 op:8000 prot:0
00aa1ac2: verifier!VsLogCall+0x42
00aa19c1: verifier!AVrfpNtFreeVirtualMemory+0x30
68925d17: kernel32!VirtualFreeEx+0x35
6892611c: kernel32!VirtualFree+0x13
75ef6525: mshtml+0x116525
75ef68af: mshtml+0x1168AF
6a20787c: ntdll!LdrpCallInitRoutine+0x14
6a211c6f: ntdll!LdrUnloadDll+0x39A
689275c1: kernel32!FreeLibrary+0x3B
77b22d69: ole32!CoQueryReleaseObject+0x1E6
77b02bd2: ole32!SetErrorInfo+0x1ED
VirtualFree (tid: 0xB4): addr:04bb0000 sz:00001000 op:4000 prot:0
00aa1ac2: verifier!VsLogCall+0x42
00aa19c1: verifier!AVrfpNtFreeVirtualMemory+0x30
68925d17: kernel32!VirtualFreeEx+0x35
6892611c: kernel32!VirtualFree+0x13
75ef65ae: mshtml+0x1165AE
75ef68af: mshtml+0x1168AF
6a20787c: ntdll!LdrpCallInitRoutine+0x14
6a211c6f: ntdll!LdrUnloadDll+0x39A
689275c1: kernel32!FreeLibrary+0x3B
77b22d69: ole32!CoQueryReleaseObject+0x1E6
77b02bd2: ole32!SetErrorInfo+0x1ED
Es ist in der Ausgabe ersichtlich, dass thread 0xB4 zuerst eine Seite freigegeben und dann den gesamten virtuellen Bereich freigegeben hat.
Hier sehen Sie eine Anzeige aller Vorgänge, die sich auf die Adresse 0x4BB1000 auswirken:
0:001> !avrf -vs -a 4bb1000
Searching in vspace log for address 04bb1000 ...
VirtualFree (tid: 0xB4): addr:04bb0000 sz:00400000 op:8000 prot:0
00aa1ac2: verifier!VsLogCall+0x42
00aa19c1: verifier!AVrfpNtFreeVirtualMemory+0x30
68925d17: kernel32!VirtualFreeEx+0x35
6892611c: kernel32!VirtualFree+0x13
75ef6525: mshtml+0x116525
75ef68af: mshtml+0x1168AF
6a20787c: ntdll!LdrpCallInitRoutine+0x14
6a211c6f: ntdll!LdrUnloadDll+0x39A
689275c1: kernel32!FreeLibrary+0x3B
77b22d69: ole32!CoQueryReleaseObject+0x1E6
77b02bd2: ole32!SetErrorInfo+0x1ED
VirtualFree (tid: 0xB4): addr:04bb1000 sz:00001000 op:4000 prot:0
00aa1ac2: verifier!VsLogCall+0x42
00aa19c1: verifier!AVrfpNtFreeVirtualMemory+0x30
68925d17: kernel32!VirtualFreeEx+0x35
6892611c: kernel32!VirtualFree+0x13
75ef65ae: mshtml+0x1165AE
75ef68af: mshtml+0x1168AF
6a20787c: ntdll!LdrpCallInitRoutine+0x14
6a211c6f: ntdll!LdrUnloadDll+0x39A
689275c1: kernel32!FreeLibrary+0x3B
77b22d69: ole32!CoQueryReleaseObject+0x1E6
77b02bd2: ole32!SetErrorInfo+0x1ED
VirtualAlloc (tid: 0xB4): addr:04bb0000 sz:00010000 op:1000 prot:4
00aa1ac2: verifier!VsLogCall+0x42
00aa1988: verifier!AVrfpNtAllocateVirtualMemory+0x37
68925ca3: kernel32!VirtualAllocEx+0x61
68926105: kernel32!VirtualAlloc+0x16
75ef63f3: mshtml+0x1163F3
VirtualAlloc (tid: 0xB4): addr:04bb0000 sz:00400000 op:2000 prot:4
00aa1ac2: verifier!VsLogCall+0x42
00aa1988: verifier!AVrfpNtAllocateVirtualMemory+0x37
68925ca3: kernel32!VirtualAllocEx+0x61
68926105: kernel32!VirtualAlloc+0x16
75ef63d9: mshtml+0x1163D9
Wenn Sie diese Ausgabe lesen möchten, denken Sie daran, dass die Einträge beginnend mit dem neuesten gespeichert werden. Daher zeigt dieses Protokoll, dass thread 0xB4 einem großen Bereich zugeordnet, in dem ein Commit für eine Seite ausgeführt wurde. Später wurde die Seite freigegeben und dann die gesamte virtuelle Region freigegeben.
Weitere Informationen
Application Verifier – Übersicht
Application Verifier – Testen von Anwendungen
Application Verifier – Tests in Application Verifier