Freigeben über


Anwendungsüberprüfung – Debuggen von Stopps der Anwendungsüberprüfung

Debuggerinstallation und -setup

Einige Anwendungsüberprüfungsaktionen können dazu führen, dass eine Ausnahme ausgelöst wird. Der Debugger muss so konfiguriert sein, dass diese Ausnahmen beim zweiten Auftreten abgefangen werden, da der Application Verifier selbst die ersten Ausnahmen abfängt.

Die ausgelösten Ausnahmen sind drei Typen:

  • Eine Ausnahme für Zugriffsverletzungen (0xC0000005) wird generiert, wenn die Heapoption einen Heappufferüberlauf erkennt. In einigen Fällen kann auch die Option "Systempfadverwendung überprüfen" einen Zugriffsverstoß verursachen.

  • Eine ungültige Handle-Ausnahme (0xC0000008) wird generiert, wenn die Option "Ungültige Handle-Nutzung erkennen" einen ungültigen Handle-Vorgang erkennt.

  • Eine Stapelüberlaufausnahme (0xC00000FD) wird generiert, wenn die Überprüfung auf geeignete Stapeloption erkennt, dass der anfängliche Stapel zu kurz war.

Eine Möglichkeit, sich auf diese Ereignisse vorzubereiten, besteht darin, den Debugger wie folgt in einer 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ültige Handles und Stapelüberläufe als Ausnahmen für zweite Chance abzufangen:

0:000> sxd av 

0:000> sxd ch 

0:000> sxd sov 1

Es ist theoretisch möglich, Application Verifier über einen Kerneldebugger zu steuern. Dies wird jedoch nicht empfohlen . Dies erfordert häufig die Verwendung der Befehle ".process" und ".pagein", aber sie bietet Ihnen nicht mehr Leistung als die Verwendung eines Debuggers im Benutzermodus.

Installieren der Debugtools

Informationen zum Herunterladen der neuesten Version der Tools finden Sie unter "Debuggingtools für Windows herunterladen".

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 ausgeführt wie die fehlgeschlagene Anwendung.

In diesem Fall ist keine bestimmte Hardwareeinrichtung erforderlich. In diesem Fall sind die Begriffe Hostcomputer und Zielcomputer 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 gedebuggt wird. Wenn es sich um eine Anwendung handelt, die Sie geschrieben haben, 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 Remotedebugging ausführen, hängt der Speicherort der Symboldatei von der verwendeten Methode ab:

  • Wenn Sie Remotedebugging über den Debugger durchführen, sollten sich die Symboldateien auf dem Computer mit dem Debuggingserver befinden.

  • Wenn Sie das Remotedebugging über remote.exedurchführen, sollten sich die Symboldateien auf dem Computer mit dem Debugger befinden.

  • Wenn Sie Remotedebugging über einen Prozessserver oder einen KD-Verbindungsserver durchführen, sollten sich die Symboldateien auf dem 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 dem Windows-Debugging".

Konfigurieren der Anwendungsüberprüfung mit dem Debugger mithilfe der Befehlszeile

Zum Konfigurieren von Application Verifier können Sie die Befehlszeile CDB oder NTSD verwenden.

Verwenden Sie die folgende Befehlszeile:

cdb OtherOptions -vf:Flags Target

Dabei ist Target der Name der Zielanwendung, und Flags gibt die gewünschten Application Verifier-Optionen 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-PRÜFUNGEN
00000004 BEHANDELN VON PRÜFUNGEN
00000008 Überprüfungen der geringen Ressourcenauslastung von SIM-Karten
00000020 TLS-PRÜFUNGEN
00000040 SCHMUTZIGE STAPEL
00000200 GEFÄHRLICHE APIS
00001000 AUSNAHMEPRÜFUNGEN
00002000 SPEICHERÜBERPRÜFUNGEN
00020000 VERSCHIEDENE PRÜ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 erstellt wurden. Weitere Informationen zur Erweiterung !arvrf finden Sie in den Debuggerdokumenten unter !avrf .

Syntax

!avrf

Der Befehl "!avrf" ohne Parameter zeigt die Einstellungen für die Anwendungsüberprüfung und Informationen zu den aktuellen und vorherigen Application Verifier-Unterbrechungen an, falls vorhanden.

!avrf –vs { Length | -aAddress }

Zeigt das Operationsprotokoll des virtuellen Raums an. Length gibt die Anzahl der Datensätze an, die beginnend mit der letzten angezeigt werden sollen. Adresse 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 Heap-Operationenprotokoll an. Adresse gibt die Heapadresse an. Die Datensätze der Heap-Vorgänge, die diese Heap-Adresse 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 beginnend mit der letzten angezeigt werden sollen. Adresse gibt die Adresse des kritischen Abschnitts an. Datensätze für den bestimmten kritischen Abschnitt werden angezeigt, wenn die Adresse angegeben wird.

!avrf -dlls [ Length ]

Zeigt das DLL-Lade-/Entladeprotokoll an. Length gibt die Anzahl der Datensätze an, die beginnend mit der 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. Bei untergeordneten Threads werden auch die Stapelgröße und die durch den übergeordneten Thread festgelegten 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 Stapelablaufverfolgungen für verschiedene Vorgänge enthalten, z. B. das Ändern der Threadaffinitätsmaske, das Ändern der Threadpriorität, das Veröffentlichen von Threadnachrichten, das Initialisieren von COM und das Aufheben der Initialisierung von COM aus 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. Das Angeben einer Adresse zeigt Datensätze an, die sich auf die entsprechende SRW-Sperradresse beziehen. Wenn "Length" zusammen mit der Adresse angegeben wird, werden alle SRW-Sperren innerhalb dieses Adressbereichs angezeigt. Die Option -stats gibt die SRW Locks-Statistiken aus.

!avrf -leak [ -m ModuleName ] [ -r ResourceType ] [ -a Address ] [ -t ]

Zeigt das hervorragende Ressourcenprotokoll an. Diese Ressourcen können zu einem bestimmten Zeitpunkt Lecks sein oder nicht. Durch Angeben von ModuleName (einschließlich der Erweiterung) werden alle ausstehenden Ressourcen im angegebenen Modul angezeigt. Wenn Sie ResourceType angeben, werden ausstehende Ressourcen dieses bestimmten Ressourcentyps angezeigt. Durch das Spezifizieren einer Adresse werden Aufzeichnungen von ausstehenden Ressourcen mit dieser Adresse angezeigt. ResourceType kann eine der folgenden Sein:

  • Heap: Zeigt Heap-Zuordnungen mit Win32-Heap-APIs an
  • Lokal: Zeigt lokale/globale Zuordnungen an.
  • CRT: Zeigt Zuordnungen mithilfe von CRT-APIs an
  • Virtuell: Zeigt virtuelle Reservierungen an
  • BSTR: Zeigt BSTR-Zuordnungen an
  • Registrierung: Zeigt den Registrierungsschlüssel an, der geöffnet wird.
  • Power: Zeigt Power Notification-Objekte an
  • Handle: Zeigt Thread-, Datei- und Ereigniszuordnungen an

!avrf –trace TraceIndex

Zeigt eine Stapelablaufverfolgung für den angegebenen Ablaufverfolgungsindex an. Einige Strukturen verwenden diese 16-Bit-Indexnummer, um eine Stapelverfolgung zu identifizieren. Dieser Index verweist auf eine Position innerhalb der Stack-Trace-Datenbank. Wenn Sie eine solche Struktur analysieren, finden Sie diese Syntax nützlich.

!avrf -cnt

Zeigt eine Liste der globalen Zähler an.

!avrf -brk [ BreakEventType ]

Gibt an, dass es sich um einen Unterbrechungsereignisbefehl handelt. Wenn !avrf -brk ohne zusätzliche Parameter verwendet wird, werden die Einstellungen für das Unterbrechungsereignis angezeigt. BreakEventType gibt die Typnummer des Unterbrechungsereignisses an. Verwenden Sie !avrf -brkfür eine Liste möglicher Typen .

!avrf -flt [ EventTypeProbability ]

Gibt an, dass dies ein Fehlereinfügungskommando ist. Wenn !avrf -flt ohne zusätzliche Parameter verwendet wird, werden die aktuellen Fehlereinfügungseinstellungen angezeigt. EventType gibt die Typnummer des Ereignisses an. Die 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

Verursacht, dass der Application Verifier jedes Mal in den Debugger einbricht, wenn dieser Fehler ausgelöst wird.

!avrf -flt stacks Length

Zeigt die Länge der Stapelablaufverfolgungen für die letzten 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 Zielbereichs oder Ausschlussbereichs an. End gibt die Endadresse des Zielbereichs oder des Ausschlussbereichs an. Modul gibt den Namen eines Moduls an, das gezielt oder ausgeschlossen werden soll. Das Modul sollte den vollständigen Modulnamen enthalten, einschließlich der .exe oder .dll Erweiterung. Pfadinformationen sollten nicht eingeschlossen werden. Das Angeben aller bewirkt, dass alle Ziel- oder Ausschlussbereiche zurückgesetzt werden.

!avrf -skp [ StartEnd | dll Module | all | Time ]

Gibt an, dass es sich um einen Ausschlussbereichsbefehl handelt. Start gibt die Anfangsadresse des Zielbereichs oder Ausschlussbereichs an. End gibt die Endadresse des Zielbereichs oder des Ausschlussbereichs an. Modul gibt den Namen eines Moduls an, das gezielt oder ausgeschlossen werden soll. Das Modul sollte den vollständigen Modulnamen enthalten, einschließlich der .exe oder .dll Erweiterung. Pfadinformationen sollten nicht eingeschlossen werden. Durch das Angeben von "alle" werden alle Zielbereiche oder Ausschlussbereiche zurückgesetzt. Wenn Sie "Time" angeben, werden alle Fehler nach dem Fortsetzen der Ausführung für Time Millisekunden unterdrückt.

Im Folgenden finden Sie die Ausgabe des Befehls "!avrf" im Debugger.

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.

!avrf-Erweiterungskommentare

Wenn die Erweiterung !avrf ohne Parameter verwendet wird, werden die aktuellen Application Verifier-Optionen angezeigt.

Die Erweiterung !avrf verwendet die Exts.dll im Debugger.

Wenn ein Application Verifier Stop aufgetreten ist, zeigt die Erweiterung !avrf ohne Parameter die Art des Stopps und was verursacht wurde.

Wenn Symbole für ntdll.dll und verifier.dll fehlen, generiert die Erweiterung !avrf eine Fehlermeldung.

Fortsetzbare und nicht fortsetzbare Stopps

Debuggen eines fortlaufenden Stopps

Hier ist ein Beispiel für eine Ausnahme eines ungültigen Handles, die durch die Option "Ungültiges Handle erkennen" ausgelöst wurde.

Zuerst 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 die Meldung Besagt, dass dieser Application Verifier-Stopp fortgesetzt werden kann. Nachdem Sie verstanden haben, was geschehen ist, können Sie die Zielanwendung weiter ausführen.

Zuerst 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).

Die letzte Zeile dieser Anzeige fasst das Problem zusammen.

Möglicherweise möchten Sie sich an diesem Punkt 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 teilt ihnen die Meldung mit, dass dieser Application Verifier Stop nicht fortgesetzt werden kann. Der Fehler ist zu schwerwiegend, als dass damit fortgefahren werden kann, und es gibt keine Möglichkeit für den 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.

Die letzte Zeile dieser Anzeige fasst das Problem zusammen.

Möglicherweise möchten Sie sich an diesem Punkt auch einige Protokolle ansehen. Möglicherweise möchten Sie an diesem Punkt den Befehl ".restart" (Target Application neu starten) verwenden. Oder vielleicht möchten Sie Ihre Application Verifier-Sitzung beenden und mit dem Beheben der Fehler in Ihrem Code beginnen.

Debuggen kritischer Abschnittsfehler

!cs Debugger-Erweiterung

!cs kann sowohl im Benutzermodusdebugger als auch im Kerneldebugger verwendet werden, um Informationen zu kritischen Abschnitten im aktuellen Prozess anzuzeigen. Weitere Informationen zur Erweiterung !cs finden Sie in den Debuggerdokumenten unter !cs .

Das Abstimmen von Symbolen mit Typinformationen ist erforderlich, insbesondere für ntdll.dll.

Die Syntax für diese Erweiterung lautet:

!cs [-s] – Alle aktiven kritischen Abschnitte im aktuellen Prozess abbilden.

!cs [-s] Adresse – kritischen Abschnitt an dieser Adresse anzeigen.

!cs [-s] -d Adresse - Speicherabbild des kritischen Abschnittes, der der DebugInfo an dieser Adresse entspricht.

-s wird die Stapelablaufverfolgung bei der Initialisierung eines kritischen Abschnitts ausgeben, wenn sie verfügbar ist.

Beispiele

Ausgeben von Informationen über einen kritischen Abschnitt mithilfe seiner Adresse

0:001> ! cs 0x7803B0F8

Critical section   = 0x7803B0F8 (MSVCRT!__app_type+0x4)
DebugInfo          = 0x6A262080
NOT LOCKED
LockSemaphore      = 0x0
SpinCount          = 0x0

Ausgabe von Informationen zu einer kritischen Sektion mithilfe ihrer Adresse, einschließlich Initialisierungs-Stack-Trace

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

Ausgeben von Informationen über eine kritische Sektion mithilfe der Debug-Info-Adresse

0:001> !cs -d 0x6A262080

DebugInfo          = 0x6A262080
Critical section   = 0x7803B0F8 (MSVCRT!__app_type+0x4)
NOT LOCKED
LockSemaphore      = 0x0
SpinCount          = 0x0

Informationen über einen kritischen Abschnitt mittels seiner Debug-Informationsadresse abrufen, einschließlich Initialisierungs-Stack-Trace.

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

Ausgabe von Informationen über alle aktiven kritischen Abschnitte im aktuellen Prozess

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
.....

Ausgabe von Informationen zu allen aktiven kritischen Bereichen im aktuellen Prozess, einschließlich Initialisierungs-Stapelablaufverfolgung.


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 Befehl !avrf -ex Length Extension verwenden, um die letzten Ausnahmen anzuzeigen. "Length" gibt die Anzahl der Ausnahmen an. Wenn Länge nicht angegeben wird, werden alle Ausnahmen angezeigt.

Hier ist ein 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 Handleablaufverfolgung für den Prozess aktiviert ist – sie wird automatisch aktiviert, wenn die Handleüberprüfung im Anwendungsverifizierer aktiviert ist. Stack-Traces werden jedes Mal gespeichert, wenn der Prozess einen Handle öffnet oder schließt oder wenn er auf einen ungültigen Handle verweist. Weitere Informationen zur Erweiterung !htrace finden Sie in den Debuggerdokumenten unter !htrace .

Die Syntax des Kerneldebuggers für diese Erweiterung lautet:

!htrace [ handle [process] ]

Wenn kein Handle angegeben ist oder 0 ist, werden Informationen zu allen Handles im Prozess angezeigt. Wenn kein Prozess angegeben ist, wird der aktuelle Prozess verwendet.

Die Syntax des Debuggers für den Benutzermodus lautet:

!htrace [handle]

Die Debuggererweiterung für den Benutzermodus zeigt immer Informationen zum aktuellen Debugprozess an.

Beispiele

Abbildinformationen zum Handle 7CC im 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.

Ausgabe von Informationen zu allen Handles im 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.

Daten 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

Heap-Prüfer-Debugger-Erweiterung

Die Heap-Verifier-Debugger-Erweiterung ist Teil der Erweiterung !heap (NT-Heap-Debugger-Erweiterung). Mit !heap -? können Sie einfache Hilfe erhalten. oder umfangreicher mit !heap -p -? . Die aktuelle Erweiterung erkennt nicht eigenständig, ob der Seitenheap für einen Prozess aktiviert ist, und reagiert nicht entsprechend. Der Benutzer der Erweiterung muss nun wissen, dass der Seitenheap aktiviert ist und Befehle verwendet, die mit dem Präfix !heap -p vorangestellt sind. Weitere Informationen zur Erweiterung !htrace finden Sie unter !heap in den Debuggerdokumenten.

!heap -p

Gibt die Adressen aller im Prozess erstellten vollständigen Seitenhaufen aus.

!heap -p -h ADDRESS-OF-HEAP

Vollständiges Abbild des Full Page Heaps bei ADDRESS-OF-HEAP.

!heap -p -a ADDRESS

Versucht herauszufinden, ob ein Heap-Block an ADDRESS vorhanden ist. Dieser Wert muss nicht die Adresse des Anfangs des Blocks sein. Der Befehl ist nützlich, wenn es keinen Hinweis auf die Art eines Speicherbereichs gibt.

Heap-Vorgangsprotokoll

Das Heap-Vorgangsprotokoll verfolgt alle Heap-Routinen. Dazu gehören HeapAlloc, HeapReAlloc und HeapFree.

Sie können den !avrf -hp Length Erweiterungsbefehl 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 Heap-Raumvorgänge anzuzeigen, die die angegebene Adresse beeinflusst haben. Für einen Zuordnungsvorgang reicht es aus, dass die Adresse im zugeordneten Heap-Block 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 Heap-Funktion 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 wurde oder an eine freie Routine übergeben wurde.
  • Die Größe der Region, die am Anruf beteiligt ist.
  • Die Stack-Trace des Anrufs.

Die neuesten Einträge werden zuerst angezeigt.

In diesem Beispiel werden die beiden neuesten 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 ziemlich viel Detektivarbeit, um das ganze Bild zu bekommen.

Zugriffsverletzung auf nicht zugänglicher Seite

Dies geschieht, wenn der vollständige Seiten-Heap aktiviert ist und die getestete Anwendung über das Ende des Puffers hinausgeht. Es kann auch passieren, wenn es einen freigegebenen Block berührt. Um zu verstehen, was die Art der Adresse ist, auf der 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 frei) überprüft der Heap-Manager der Seite, ob der Block alle Füllmuster intakt hat und der Blockheader konsistente Daten hat. Wenn dies nicht der Fall ist, erhalten Sie einen Prüferstopp.

Wenn der Block ein Full Page Heap-Block ist (z. B. wenn Sie sicher wissen, dass der Full Page Heap für alle Zuordnungen aktiviert ist), dann können Sie "!heap –p –a ADDRESS" verwenden, um herauszufinden, welche Merkmale der Block aufweist.

Wenn der Block ein Light Page Heap-Block ist, müssen Sie die Startadresse für den Blockheader ermitteln. Sie finden die Startadresse, indem Sie 30-40 Bytes unter der gemeldeten Adresse dumpingn und nach den magischen Start-/End-Mustern für einen Blockheader suchen (ABCDAAAA, ABCDBBBB, ABCDAAA9, ABCDBBBA).

Die Kopfzeile enthält alle Informationen, die Sie benötigen, um den Fehler zu verstehen. Insbesondere werden die magischen Muster erkennen, ob der Block zugewiesen oder frei ist, und ob es sich um einen Light Page Heap oder einen Full Page Heap Block handelt. Die hier aufgeführten Informationen müssen sorgfältig mit dem beleidigenden Anruf 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 gut aus, aber Sie müssen feststellen, dass das erste Byte nach dem Ende des Headers (erstes Byte nach der magischen Zahl 0xDCBAXXXX) eine andere Adresse hat als die im Aufruf.

Spezielle Füllzeiger

Der Page-Heap-Manager füllt die Benutzerzuweisung mit Werten, die wie Kernelzeiger aussehen. Dies geschieht, wenn der Block freigegeben wird (Füllwert ist F0) und wenn der Block zugewiesen wird, aber keine Anforderung gestellt wird, dass der Block null sein soll (Füllwert ist E0 für den Heap der Hellen Seite und C0 für den Heap der ganzen Seite). Die nicht-nullierten Zuordnungen sind typisch für malloc-/new-Nutzer. Wenn ein Fehler (Zugriffsverletzung) auftritt, bei dem ein Lese-/Schreibzugriff auf Adressen wie F0F0F0F0, E0E0E0E0 oder C0C0C0C0 versucht wird, dann haben Sie wahrscheinlich einen dieser Fälle getroffen.

Ein Lese-/Schreibvorgang bei F0F0F0F0 bedeutet, dass ein Speicherblock verwendet wurde, nachdem er freigegeben wurde. Leider benötigen Sie einige Detektivarbeit, um herauszufinden, welcher Block das verursacht hat. Sie müssen die Stack-Trace des Fehlers abrufen und dann den Code für die Funktionen im Stack überprüfen. Eine der Parteien könnte eine falsche Annahme darüber haben, dass eine Zuteilung noch aktiv ist.

Ein Lese-/Schreibzugriff bei E0E0E0E0/C0C0C0C0 bedeutet, dass die Anwendung die Zuordnung nicht ordnungsgemäß initialisiert hat. Dies erfordert auch die Codeinspektion der Funktionen im aktuellen Stack-Trace. Hier ist es ein Beispiel für diese Art von Fehler. Bei einem Testprozess bemerkte man eine Zugriffsverletzung während der Durchführung von HeapFree auf die Adresse E0E0E0E0. Es stellte sich heraus, dass der Test eine Struktur zugewiesen, nicht richtig initialisiert und dann den Destruktor des Objekts aufgerufen hat. Da ein bestimmtes Feld nicht null war (es enthielt E0E0E0E0), wurde darauf die Löschoperation ausgeführt.

Technische Details zur Seite Heap

Um Heapbeschädigungen (Überlauf oder Unterläufe) zu erkennen, ändert AppVerifier die Art und Weise, wie Speicher zugewiesen wird, indem der angeforderte Speicher entweder mit vollständigen nicht beschreibbaren Seiten oder mit speziellen Tags vor und nach dem zugewiesenen Speicher aufgefüllt wird. AppVerifier führt dies aus, indem es Verifier.dll in den überprüften Prozess lädt und einige der von der Anwendung aufgerufenen Win32-Heap-APIs auf die entsprechenden Verifier.dll-APIs umleitet.

Beim Auffüllen des angeforderten Arbeitsspeichers mit vollständigen nicht beschreibbaren Seiten (die EINSTELLUNG "VOLLSTÄNDIG" ist im Abschnitt mit den Seiten heap-Eigenschaften aktiviert und ist die Standardeinstellung), verbraucht AppVerifier eine große Menge virtuellen Arbeitsspeichers, hat aber den Vorteil, dass Heap-Beschädigungsereignisse in Echtzeit zwischengespeichert werden, wenn der Überlauf oder Unterlauf auftritt. Denken Sie daran, dass der Speicher in diesem Modus entweder wie folgt aussieht [AppVerifier Read-Only Heap-Seite (4k)] [Menge an Arbeitsspeicher, der von der Anwendung im Test angefordert wird] oder wie folgt [Menge an Arbeitsspeicher, der von der Anwendung im Test angefordert wird] [AppVerifier Read-Only Heap-Seite (4k)].

Die Heapüberprüfung platziert eine Schutzseite entweder am Anfang oder am Ende der Speicherzuweisung, abhängig von der Backward-Eigenschaft. Wenn "Backward" auf "False" festgelegt ist, was der Standardwert ist, wird am Ende der Zuordnung eine Schutzseite platziert, um Pufferüberläufe abzufangen. Wenn es auf "True" festgelegt ist, wird die Schutzseite am Anfang der Speicherzuweisung platziert, um Pufferunterläufe zu erfassen.

Beim Auffüllen des angeforderten Speichers mit speziellen Tags (ermöglicht durch das Deaktivieren des Kontrollkästchens "Vollständig" in den Heap-Eigenschaften) überprüft AppVerifier den Speicher und warnt Sie, wenn dieser freigegeben wird. Das Hauptproblem bei der Verwendung dieser Technik besteht darin, dass es einige Fälle gibt, in denen die Speicherbeschädigung nur erkannt wird, wenn der Speicher freigegeben wird (die mindeste Menge des Speicherblocks beträgt 8 Byte), sodass bei einer 3-Byte-Variablen oder einem 5-Byte-Überlauf nicht sofort erkannt wird.

Bei einem Unterlaufereignis wird versucht, auf 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 Vollseiten-Heapmodus auch diese Fehler erkennt, da er Auffüll- und Schutzseiten verwendet. Der Grund, warum Sie einen Light Page Heap verwenden würden, besteht darin, dass Ihr Computer die hohen Speicheranforderungen des vollständigen Seitenspeichers nicht tolerieren kann.

Bei speicherintensiven Anwendungen oder wenn appVerifier während langer Zeiträume (z. B. Stresstests) verwendet werden muss, ist es besser, normale (leichte) Heaptests anstelle des vollständigen Modus aufgrund der Leistungsbeeinträchtigung auszuführen. Wenn Sie jedoch auf ein Problem stoßen, aktivieren Sie den Full Page Heap, um das Problem weiter zu untersuchen.

Anwendungen, die benutzerdefinierte Heaps verwenden (ein Heap, der die Implementierung des Heaps des Betriebssystems umgeht), profitieren möglicherweise nicht vollständig von der Verwendung des Seitenheaps oder es können sogar Fehlfunktionen auftreten, wenn sie aktiviert ist.

Debuggen von Speicherfehlern

Die Debugger-Erweiterung für die Speicherprüfung

Das Protokoll des virtuellen Raumvorgangs verfolgt alle Routinen, die den virtuellen Raum eines Prozesses auf irgendeine Weise ändern. Dazu gehören VirtualAlloc, VirtualFree, MapViewOfFile und UnmapViewOfFile.

Sie können den !avrf -vs Length Erweiterungsbefehl 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 die angegebene Adresse beeinflusst haben. Für eine Zuordnung reicht es aus, dass die Adresse im zugewiesenen Block enthalten ist. Die genaue Adresse des Anfangs der Region muss kostenlos angegeben werden.

Für jeden Eintrag im Protokoll werden die folgenden Informationen angezeigt:

  • Die aufgerufene Funktion
  • 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 wurde oder an eine freie Routine übergeben wurde.
  • Die Größe der Region, die am Anruf beteiligt ist
  • Der Typ des Speichervorgangs (der AllocationType-Parameter)
  • Der Typ des angeforderten Schutzes
  • Die Stapelablaufverfolgung des Anrufs

Beispiele

Die neuesten Einträge werden zuerst angezeigt.

Im folgenden Beispiel werden die beiden zuletzt verwendeten 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 kann aus der Ausgabe gesehen werden, dass Thread 0xB4 zuerst eine Seite zurückgenommen und dann die gesamte virtuelle Region 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

Um diese Ausgabe zu lesen, denken Sie daran, dass die Einträge beginnend mit dem neuesten Eintrag ausgegeben werden. Daher zeigt dieses Protokoll, dass der Thread 0xB4 eine große Region zugeordnet und in dieser eine Seite zugesichert hat. Später wurde die Seite aufgehoben und dann die gesamte virtuelle Region freigegeben.

Siehe auch

Application Verifier – Übersicht

Application Verifier – Testen von Anwendungen

Application Verifier – Tests innerhalb von Application Verifier

Application Verifier - Stoppcodes und Definitionen

Application Verifier – Häufig gestellte Fragen