Compartir a través de


Comprobador de aplicaciones: depuración de las paradas del comprobador de aplicaciones

Instalación y instalación del depurador

Algunas acciones del Comprobador de aplicaciones pueden provocar una excepción. El depurador debe establecerse para detectar estas excepciones en la segunda oportunidad, ya que el propio Comprobador de aplicaciones controlará las primeras excepciones de probabilidad.

Las excepciones generadas son de tres tipos:

  • Se genera una excepción de infracción de acceso (0xC0000005) si la opción montón detecta una saturación del búfer del montón. En algunos casos, la opción Comprobar el uso de la ruta de acceso del sistema también puede provocar una infracción de acceso.

  • Se genera una excepción de identificador no válida (0xC0000008) cuando la opción Detectar uso de identificador no válido detecta una operación de identificador no válida.

  • Se genera una excepción de desbordamiento de pila (0xC00000FD) cuando la opción Comprobar la pila adecuada detecta que la pila inicial era demasiado corta.

Una manera de prepararse para estos eventos es iniciar el depurador en una línea de comandos de la siguiente manera:

windbg -xd av -xd ch -xd sov ApplicationCommandLine

o

cdb -xd av -xd ch -xd sov ApplicationCommandLine

Si ya ha iniciado el depurador, puede usar el comando sxd (Establecer excepciones) para detectar todas las infracciones de acceso, identificadores no válidos y desbordamientos de pila como excepciones de segunda oportunidad:

0:000> sxd av 

0:000> sxd ch 

0:000> sxd sov 1

En teoría, es posible controlar application Verifier a través de un depurador de kernel. Sin embargo, esto no se recomienda: requiere un uso frecuente de los comandos .process y .pagein, pero no proporciona más poder que usar un depurador en modo de usuario.

Instalación de las herramientas de depuración

Para descargar la versión más reciente de las herramientas, consulte Descargar herramientas de depuración para Windows.

Configuración de hardware para la depuración de User-Mode

La depuración en modo de usuario generalmente se realiza en una sola máquina: el depurador se ejecuta en el mismo equipo que la aplicación que produjo un error.

En este caso, no se requiere ninguna configuración de hardware específica. En este tema, los términos equipo host y equipo de destino son intercambiables en este caso.

Configuración de software para la depuración de User-Mode

Configuración básica de User-Mode: para poder comenzar la depuración en modo de usuario, debe descargar los archivos de símbolos necesarios y establecer determinadas variables de entorno.

Archivos de símbolos

Debe descargar los archivos de símbolos para el proceso en modo de usuario que se está depurando. Si se trata de una aplicación que ha escrito, debe compilarse con archivos de símbolos completos. Si es una aplicación comercial, los archivos de símbolos pueden estar disponibles en un servidor web o para su descarga, póngase en contacto con el fabricante.

Si va a realizar la depuración remota, la ubicación del archivo de símbolos depende del método que use:

  • Si va a realizar la depuración remota a través del depurador, los archivos de símbolos deben estar en el equipo con el servidor de depuración.

  • Si va a realizar la depuración remota a través de remote.exe, los archivos de símbolos deben estar en el equipo con el depurador.

  • Si va a realizar la depuración remota a través de un servidor de procesos o un servidor de conexión KD, los archivos de símbolos deben estar en el equipo con el cliente inteligente.

  • Si está controlando el depurador en modo de usuario desde el depurador de kernel, los archivos de símbolos deben estar en ambos equipos.

Configuración de variables de entorno

El depurador usa una variedad de variables de entorno para indicar una serie de configuraciones importantes.

Para obtener más información sobre los depuradores, consulte Introducción con depuración de Windows.

Configuración del comprobador de aplicaciones con el depurador mediante la línea de comandos

Para configurar Application Verifier, puede usar la línea de comandos CDB o NTSD.

Use la siguiente línea de comandos:

cdb OtherOptions -vf:Flags Target

Donde Target es el nombre de la aplicación de destino y Flags especifica las opciones de Comprobador de aplicaciones deseadas que se van a aplicar a este destino.

Las marcas deben ser una suma de los bits que representan las opciones deseadas. Los valores de bits individuales son los siguientes:

Valor de marca Significado
00000001 COMPROBACIONES DEL MONTÓN
00000004 CONTROL DE COMPROBACIONES
00000008 COMPROBACIONES DE SIM DE RECURSOS BAJOS
00000020 COMPROBACIONES DE TLS
00000040 PILAS SUCIAS
00000200 API PELIGROSAS
00001000 COMPROBACIONES DE EXCEPCIONES
00002000 COMPROBACIONES DE MEMORIA
00020000 COMPROBACIONES VARIAS
00040000 COMPROBACIONES DE BLOQUEO

Depuración con !avrf

La extensión !avrf controla la configuración de Application Verifier y muestra una variedad de salidas generadas por Application Verifier. Para obtener más información sobre la extensión !arvrf, vea !avrf en la documentación del depurador.

Syntax

!avrf

El comando !avrf sin parámetros muestra la configuración del Comprobador de la aplicación y la información sobre los saltos actuales y anteriores del Comprobador de aplicaciones, si los hay.

!avrf –vs { Length | -aAddress }

Muestra el registro de operaciones de espacio virtual. Length especifica el número de registros que se van a mostrar a partir de la más reciente. Address especifica la dirección virtual. Se mostrarán los registros de las operaciones virtuales que contienen esta dirección virtual.

!avrf -hp { Length | -a Address }

Muestra el registro de operaciones del montón. Address especifica la dirección del montón. Se mostrarán los registros de las operaciones del montón que contienen esta dirección del montón.

!avrf -cs { Length | -a Address }

Muestra el registro de eliminación de la sección crítica. Length especifica el número de registros que se van a mostrar a partir de la más reciente. Address especifica la dirección de sección crítica. Los registros de la sección crítica determinada se muestran cuando se especifica Address.

!avrf -dlls [ Length ]

Muestra el registro de carga o descarga de DLL. Length especifica el número de registros que se van a mostrar a partir de la más reciente.

!avrf -trm

Muestra un registro de todos los subprocesos terminados y suspendidos.

!avrf -ex [ Length ]

Muestra el registro de excepciones. Comprobador de aplicaciones realiza un seguimiento de todas las excepciones que se producen en la aplicación.

!avrf -threads [ ThreadID ]

Muestra información sobre los subprocesos en el proceso de destino. En el caso de los subprocesos secundarios, también se muestran el tamaño de la pila y las marcas CreateThread especificadas por el elemento primario. Al proporcionar un identificador de subproceso solo se mostrará información para ese subproceso determinado.

!avrf -tp [ ThreadID ]

Muestra el registro del grupo de subprocesos. Este registro puede contener seguimientos de pila para varias operaciones, como cambiar la máscara de afinidad de subproceso, cambiar la prioridad del subproceso, publicar mensajes de subprocesos, inicializar COM e inicializar COM desde la devolución de llamada del grupo de subprocesos. Al proporcionar un identificador de subproceso solo se mostrará información para ese subproceso determinado.

!avrf -srw [ Address | Address Length ] [ -stats ]

Muestra el registro de lector y escritor delgado (SRW). Al especificar Dirección, se mostrarán los registros correspondientes a esa dirección de bloqueo srW. Cuando se especifica Length junto con la dirección , se muestran todos los bloqueos SRW dentro de ese intervalo de direcciones. La opción -stats volca las estadísticas de bloqueo de SRW.

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

Muestra el registro de recursos pendientes. Estos recursos pueden o no ser pérdidas en un momento dado. Al especificar ModuleName (incluida la extensión), se muestran todos los recursos pendientes en el módulo especificado. Al especificar ResourceType se muestran los recursos pendientes de ese tipo de recurso concreto. Especificar registros de volcados de dirección de recursos pendientes con esa dirección. ResourceType puede ser uno de los siguientes:

  • Montón: muestra las asignaciones del montón mediante las API de montón de Win32
  • Local: muestra asignaciones locales o globales
  • CRT: muestra las asignaciones mediante las API de CRT
  • Virtual: muestra reservas virtuales
  • BSTR: muestra asignaciones de BSTR
  • Registro: muestra la clave del Registro que se abre
  • Power: muestra objetos de notificación de energía
  • Identificador: muestra asignaciones de subprocesos, archivos y controladores de eventos

!avrf –trace TraceIndex

Muestra un seguimiento de pila para el índice de seguimiento especificado. Algunas estructuras usan este número de índice de 16 bits para identificar un seguimiento de pila. Este índice apunta a una ubicación dentro de la base de datos de seguimiento de pila. Si está analizando esta estructura, encontrará esta sintaxis útil.

!avrf -cnt

Muestra una lista de contadores globales.

!avrf -brk [ BreakEventType ]

Especifica que se trata de un comando break-event. Cuando !avrf -brk se usa sin parámetros adicionales, se muestra la configuración del evento break. BreakEventType especifica el número de tipo del evento break. Para obtener una lista de posibles tipos, use !avrf -brk.

!avrf -flt [ EventTypeProbability ]

Especifica que se trata de un comando de inyección de errores. Cuando !avrf -flt se usa sin parámetros adicionales, se muestra la configuración de inserción de errores actual. EventType especifica el número de tipo del evento. La probabilidad especifica la frecuencia con la que se producirá un error en el evento. Puede ser cualquier entero entre 0 y 1000 000 (0xF4240).

!avrf -flt break EventType

Hace que el Comprobador de aplicaciones se interrumpa en el depurador cada vez que se inserta este error.

!avrf -flt stacks Length

Muestra el número de seguimientos de pila de longitud de las operaciones insertadas por error más recientes.

!avrf -trg [ StartEnd | dll Module | all ]

Especifica que se trata de un comando de intervalo de destino. Cuando se usa -trg sin parámetros adicionales, se muestran los intervalos de destino actuales. Start especifica la dirección inicial del intervalo de destino o del intervalo de exclusión. End especifica la dirección final del intervalo de destino o del intervalo de exclusión. Module especifica el nombre de un módulo al que se va a destinar o excluir. El módulo debe incluir el nombre completo del módulo, incluida la extensión .exe o .dll. No se debe incluir la información de ruta de acceso. Especificar todas hace que se restablezcan todos los intervalos de destino o los intervalos de exclusión.

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

Especifica que se trata de un comando de intervalo de exclusión. Start especifica la dirección inicial del intervalo de destino o del intervalo de exclusión. End especifica la dirección final del intervalo de destino o del intervalo de exclusión. Module especifica el nombre de un módulo al que se va a destinar o excluir. El módulo debe incluir el nombre completo del módulo, incluida la extensión .exe o .dll. No se debe incluir la información de ruta de acceso. Especificar todas hace que se restablezcan todos los intervalos de destino o los intervalos de exclusión. Especificar tiempo hace que se supriman todos los errores de time milisegundos después de que se reanude la ejecución.

El siguiente es el resultado proporcionado por el comando !avrf en el depurador.

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 extension comments

Cuando se usa la extensión !avrf sin parámetros, muestra las opciones actuales del Comprobador de aplicaciones.

La extensión !avrf usa el Exts.dll en el depurador.

Si se ha producido una detención del comprobador de aplicaciones, la extensión !avrf sin parámetros revelará la naturaleza de la detención y lo que lo causó.

Si faltan símbolos para ntdll.dll y verifier.dll, la extensión !avrf generará un mensaje de error.

Paradas continuables y no continuables

Depuración de una detención continuable

Este es un ejemplo de una excepción de identificador no válida generada por la opción Detectar uso de identificadores no válidos.

En primer lugar, aparece el siguiente mensaje:

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

Observe que el mensaje indica que esta detención del comprobador de aplicaciones puede continuar. Después de comprender lo que ha transcurrido, puede seguir ejecutando la aplicación de destino.

En primer lugar, debe usar la extensión !avrf. Esto proporciona información sobre el error actual:

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

La última línea de esta pantalla resume el problema.

Es posible que desee examinar algunos registros en este momento. Cuando haya terminado, use el comando g (Go) para volver a iniciar la aplicación:

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

En este caso, el mensaje indica que esta detención del comprobador de aplicaciones no se puede continuar. El error es demasiado grave para que el proceso continúe ejecutándose y no hay ninguna manera de que el Comprobador de aplicaciones salva el proceso.

La extensión !avrf se puede usar para proporcionar información sobre el error actual:

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.

La última línea de esta pantalla resume el problema.

También puede que desee examinar algunos registros en este momento. Es posible que quiera usar el comando .restart (Reiniciar aplicación de destino) en este momento. O quizás prefiera finalizar la sesión del Comprobador de aplicaciones y comenzar a corregir los errores en el código.

Depuración de errores críticos en la sección

Extensión del depurador de !cs

!cs se puede usar tanto en el depurador en modo de usuario como en el depurador de kernel para mostrar información sobre las secciones críticas del proceso actual. Para obtener más información sobre la extensión !cs, vea !cs en la documentación del depurador.

Se requiere coincidencia de símbolos con información de tipo, especialmente para ntdll.dll.

La sintaxis de esta extensión es:

!cs [-s] : volcado de todas las secciones críticas activas del proceso actual.

Dirección de !cs [-s] : sección crítica de volcado de memoria en esta dirección.

!cs [-s] -d address : sección crítica de volcado correspondiente a DebugInfo en esta dirección.

-s volcará el seguimiento de la pila de inicialización de sección crítica si está disponible.

Ejemplos:

Volcado de información sobre una sección crítica mediante su dirección

0:001> ! cs 0x7803B0F8

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

Volcado de información sobre una sección crítica mediante su dirección, incluido el seguimiento de la pila de inicialización

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

Volcado de información sobre una sección crítica mediante su dirección de información de depuración

0:001> !cs -d 0x6A262080

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

Volcado de información sobre una sección crítica mediante su dirección de información de depuración, incluido el seguimiento de la pila de inicialización

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

Volcado de información sobre todas las secciones críticas activas del proceso actual

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

Volcado de información sobre todas las secciones críticas activas del proceso actual, incluido el seguimiento de la pila de inicialización.


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

Depuración de errores de excepción

El registro de excepciones registra todas las excepciones que se han producido en el proceso de destino.

Puede usar el comando de extensión !avrf -ex Length para mostrar las últimas excepciones; Length especifica el número de excepciones. Si se omite Length, se muestran todas las excepciones.

Este es un ejemplo:

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.

Depuración controla errores

!htrace se puede usar tanto en el depurador en modo de usuario como en el depurador de kernel para mostrar información de seguimiento de pila para uno o todos los identificadores de un proceso. Esta información está disponible si el seguimiento de identificadores está habilitado para el proceso; se habilita automáticamente si la comprobación de identificadores está habilitada en el comprobador de la aplicación. Los seguimientos de pila se guardan cada vez que el proceso abre o cierra un identificador o cuando hace referencia a un identificador no válido. Para obtener más información sobre la extensión !htrace, vea !htrace en la documentación del depurador.

La sintaxis del depurador de kernel para esta extensión es:

!htrace [ handle [process] ]

Si no se especifica handle o es 0, se mostrará información sobre todos los identificadores del proceso. Si no se especifica el proceso, se usará el proceso actual.

La sintaxis del depurador en modo de usuario es:

!htrace [handle]

La extensión del depurador en modo de usuario siempre muestra información sobre el proceso de desbugee actual.

Ejemplos:

Información de volcado de memoria sobre el identificador 7CC en el proceso 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.

Información de volcado de memoria sobre todos los identificadores del proceso 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.

Información de volcado de memoria sobre el identificador 7DC en el proceso actual


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.

Errores de montón de depuración

Extensión del depurador del comprobador del montón

La extensión del depurador del comprobador del montón forma parte de la extensión !heap (extensión del depurador del montón NT). Se puede obtener ayuda simple con !montón -? o más extenso con !heap -p -? . La extensión actual no detecta por sí misma si el montón de páginas está habilitado para un proceso y actúa en consecuencia. Por ahora, el usuario de la extensión debe saber que el montón de páginas está habilitado y usar comandos con el prefijo !heap -p . Para obtener más información sobre la extensión !htrace, vea !heap en la documentación del depurador.

!heap -p

Volca las direcciones de todos los montones de páginas completos creados en el proceso.

!heap -p -h ADDRESS-OF-HEAP

Volcado completo del montón de página completa en ADDRESS-OF-HEAP.

!heap -p -a ADDRESS

Intenta averiguar si hay un bloque de montón en ADDRESS. Este valor no necesita ser la dirección del inicio del bloque. El comando es útil si no hay ninguna pista sobre la naturaleza de un área de memoria.

Registro de operaciones del montón

El registro de operaciones del montón realiza un seguimiento de todas las rutinas del montón. Estos incluyen HeapAlloc, HeapReAlloc y HeapFree.

Puede usar el comando de !avrf -hp Length extensión para mostrar los últimos registros; Length especifica el número de registros.

Puede usar !avrf -hp -a Address para mostrar todas las operaciones de espacio de montón que afectaron a la dirección especificada. Para una operación de asignación, es suficiente que Address esté incluido en el bloque de montón asignado. Para una operación gratuita, se debe proporcionar la dirección exacta del principio del bloque.

Para cada entrada del registro, se muestra la siguiente información:

  • Función de montón llamada.
  • Identificador de subproceso del subproceso que llamó a la rutina.
  • La dirección implicada en la llamada: esta es la dirección devuelta por una rutina de asignación o que se pasó a una rutina gratuita.
  • Tamaño de la región implicada en la llamada.
  • Seguimiento de pila de la llamada.

Las entradas más recientes se muestran primero.

En este ejemplo, se muestran las dos entradas más recientes:

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

Escenarios típicos de depuración

Hay varios escenarios de error que se pueden encontrar. Algunos de ellos requieren un poco de trabajo de detective para obtener toda la imagen.

Infracción de acceso en la página no accesible

Esto sucede cuando el montón de página completa está habilitado si la aplicación probada accede más allá del final del búfer. También puede ocurrir si toca un bloque liberado. Para comprender cuál es la naturaleza de la dirección en la que se produjo la excepción, debe usar:

!heap –p –a ADDRESS-OF-AV

Mensaje de bloque dañado

En varios momentos durante la vigencia de una asignación (asignación, libre de usuario, libre y disponible) el administrador del montón de páginas comprueba si el bloque tiene intactos todos los patrones de relleno y el encabezado del bloque tiene datos coherentes. Si este no es el caso, obtendrá una detención del comprobador.

Si el bloque es un bloque de montón de página completa (por ejemplo, si sabe que el montón de página completa está habilitado para todas las asignaciones), puede usar "!heap –p –a ADDRESS" para averiguar cuáles son las características del bloque.

Si el bloque es un bloque de montón de páginas ligeras, debe averiguar la dirección de inicio del encabezado de bloque. Puede encontrar la dirección inicial al volcar 30-40 bytes por debajo de la dirección notificada y buscar los patrones de inicio y finalización mágicos para un encabezado de bloque (ABCDAAAA, ABCDBBBB, ABCDAAA9, ABCDBBBA).

El encabezado proporcionará toda la información que necesita para comprender el error. Especialmente, los patrones mágicos indicarán si el bloque se asigna o libera si es un montón de páginas ligeras o un bloque de montón de página completa. La información aquí debe coincidir cuidadosamente con la llamada ofendida.

Por ejemplo, si se realiza una llamada a HeapFree con la dirección de un bloque más cuatro bytes, obtendrá el mensaje dañado. El encabezado de bloque tendrá un aspecto correcto, pero tendrá que observar que el primer byte después del final del encabezado (primer byte después de 0xDCBAXXXX magic value) tiene una dirección diferente y la de la llamada.

Punteros de relleno especiales

El administrador del montón de páginas rellena la asignación de usuarios con valores que se verán como punteros del kernel. Esto sucede cuando el bloque se libera (el valor de relleno es F0) y cuando el bloque se asigna, pero no se realiza ninguna solicitud para que el bloque esté cero (el valor de relleno es E0 para el montón de páginas ligeras y C0 para el montón de página completa). Las asignaciones no ceros son típicas para usuarios malloc o nuevos. Si se produce un error (infracción de acceso) en el que se intenta realizar una lectura y escritura en direcciones como F0F0F0F0, E0E0E0E0, C0C0C0C0, lo más probable es que se alcance uno de estos casos.

Una lectura y escritura en F0F0F0F0 significa que se ha usado un bloque después de liberarlo. Desafortunadamente usted necesitará algún trabajo de detective para averiguar qué bloque causó esto. Debe obtener el seguimiento de la pila del error y, a continuación, inspeccionar el código de las funciones de la pila. Una de ellas podría suponer erróneamente que una asignación está activa.

Una lectura y escritura en E0E0E0E0/C0C0C0C0 significa que la aplicación no inicializó correctamente la asignación. Esto también requiere la inspección de código de las funciones en el seguimiento de pila actual. Este es un ejemplo de este tipo de error. En un proceso de prueba, se notó una infracción de acceso mientras se realiza un heapFree en la dirección E0E0E0E0. Resultó que la prueba asignó una estructura, no la inicializó correctamente y luego llamó al destructor del objeto. Dado que un campo determinado no era nulo (tenía E0E0E0E0 en él), llamó a delete en él.

Detalles técnicos del montón de páginas

Para detectar daños en el montón (desbordamientos o subflujos), AppVerifier modificará la forma en que se asigna la memoria rellenando la memoria solicitada con páginas no grabables completas o con etiquetas especiales antes y después de la memoria asignada. AppVerifier lo hace cargando Verifier.dll en el proceso que se está comprobando y redirigiendo algunas de las API del montón de Win32 llamadas por la aplicación a las API de Verifier.dll correspondientes.

Al rellenar la memoria solicitada con páginas completas que no se pueden escribir (la configuración FULL está habilitada en la sección de propiedades del montón de páginas y es la configuración predeterminada), AppVerifier consumirá una gran cantidad de memoria virtual, pero tiene la ventaja de que los eventos dañados del montón se almacenan en caché en tiempo real cuando se produce el desbordamiento o el flujo inferior. Recuerde que la memoria en este modo tendrá un aspecto similar al siguiente [AppVerifier Read-Only página montón (4k)] [Cantidad de memoria solicitada por la aplicación bajo prueba] o como esta [Cantidad de memoria solicitada por la aplicación bajo prueba] [AppVerifier Read-Only página montón (4k)].

La comprobación del montón colocará una página de protección al principio o al final de la asignación en función de la propiedad Backward. Si Backward está establecido en False, que es el valor predeterminado, colocará una página de protección al final de la asignación para detectar saturaciones del búfer. Si se establece en True, la página de protección se coloca al principio de la asignación para detectar las subejecutaciones del búfer.

Al rellenar la memoria solicitada con etiquetas especiales (habilitadas desactivando el elemento de casilla "Completo" en las propiedades del montón), AppVerifier comprobará y le avisará cuando se libere esta memoria. El problema principal en el uso de esta técnica es que hay algunos casos en los que solo se detectan daños en la memoria cuando se libera la memoria (la cantidad mínima de bloque de memoria es de 8 bytes), por lo que cuando se produce un desbordamiento de 3 bytes o un desbordamiento de 5 bytes, no se detectará inmediatamente.

En un evento de subflujo, se intentará escribir en una página de Read-Only. Esto desencadenará una excepción. Tenga en cuenta que esta excepción solo se puede detectar si la aplicación de destino se ejecuta en un depurador. Tenga en cuenta que el modo de montón de página completa también detectará estos errores porque usa páginas de relleno y protección. La razón por la que usaría el montón de páginas ligeras es si el equipo no puede tolerar las restricciones de memoria alta del montón de página completa.

En el caso de las aplicaciones que consumen mucha memoria o cuando es necesario usar AppVerifier durante largos períodos de tiempo (por ejemplo, pruebas de esfuerzo), es mejor ejecutar pruebas de montón normales (ligeras) en lugar del modo completo debido a la degradación del rendimiento. Sin embargo, cuando se produzca un problema, active el montón de página completa para investigar más.

Es posible que las aplicaciones que usan montones personalizados (un montón que omita la implementación del montón del sistema operativo) no obtengan la ventaja completa de usar el montón de páginas o incluso podrían funcionar mal cuando está habilitado.

Errores de memoria de depuración

Extensión del depurador de comprobador de memoria

El registro de operaciones de espacio virtual realiza un seguimiento de todas las rutinas que modifican el espacio virtual de un proceso de cualquier manera. Entre ellos se incluyen VirtualAlloc, VirtualFree, MapViewOfFile y UnmapViewOfFile.

Puede usar el comando de !avrf -vs Length extensión para mostrar los últimos registros; Length especifica el número de registros.

Puede usar !avrf -vs -a Address para mostrar todas las operaciones de espacio virtual que afectaron a la dirección especificada. Para una asignación, es suficiente que Address esté incluido en el bloque asignado. Para obtener una dirección gratuita, se debe proporcionar la dirección exacta del principio de la región.

Para cada entrada del registro, se muestra la siguiente información:

  • La función llamada
  • Identificador de subproceso del subproceso que llamó a la rutina
  • La dirección implicada en la llamada: esta es la dirección devuelta por una rutina de asignación o que se pasó a una rutina gratuita.
  • Tamaño de la región implicada en la llamada
  • Tipo de operación de memoria (el parámetro AllocationType)
  • El tipo de protección solicitado
  • Seguimiento de pila de la llamada

Ejemplos

Las entradas más recientes se muestran primero.

En el ejemplo siguiente, se muestran las dos entradas más recientes:

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

Se puede ver en la salida que el subproceso 0xB4 primero descommitió una página y, a continuación, liberó toda la región virtual.

Esta es una presentación de todas las operaciones que afectan a la dirección 0x4BB1000:

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

Para leer esta salida, recuerde que las entradas se volcarán a partir de la más reciente. Por lo tanto, este registro muestra que el subproceso 0xB4 ha asignado una región grande en la que ha confirmado una página. Más adelante, descommitió la página y, a continuación, lanzó toda la región virtual.

Consulte también

Comprobador de aplicaciones: información general

Comprobador de aplicaciones: pruebas de aplicaciones

Comprobador de aplicaciones: pruebas dentro del comprobador de aplicaciones

Comprobador de aplicaciones: códigos y definiciones de detención

Comprobador de aplicaciones: preguntas más frecuentes