Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Instalación y configuración del depurador
Algunas acciones del Comprobador de aplicaciones pueden provocar una excepción. El depurador debe configurarse para capturar estas excepciones en la segunda oportunidad, ya que Application Verifier se encargará de las excepciones de primera oportunidad.
Las excepciones generadas son de tres tipos:
Se genera una excepción de infracción de acceso (0xC0000005) si la opción de heap detecta un desbordamiento del búfer del heap. 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 potencia 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 equipos para la depuración User-Mode
La depuración en modo de usuario se realiza generalmente 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 se trata de 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 está realizando la depuración remota, la ubicación del archivo de símbolos depende del método que está usando:
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 mediante 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 de modo 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 a la 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 | VERIFICACIONES DEL HEAP |
| 00000004 | GESTIONAR COMPROBACIONES |
| 00000008 | COMPROBACIONES DE SIM EN CONDICIÓN DE RECURSOS LIMITADOS |
| 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 resultados generados por Application Verifier. Para obtener más información sobre la extensión !arvrf, consulte !avrf en los documentos del depurador.
Sintaxis
!avrf
El comando !avrf sin parámetros muestra la configuración del Comprobador de aplicaciones y la información sobre las interrupciones actuales y anteriores del Comprobador de aplicaciones, si las hay.
!avrf –vs { Length | -aAddress }
Muestra el registro de operaciones de espacio virtual. La longitud especifica el número de registros que se van a mostrar a partir de los más recientes. La dirección 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 de memoria. 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 los más recientes. La dirección especifica la ubicación de la sección crítica. Los registros de la sección crítica determinada se muestran cuando se especifica la dirección.
!avrf -dlls [ Length ]
Muestra el registro de carga/descarga de DLL. Length especifica el número de registros que se van a mostrar comenzando desde los más recientes.
!avrf -trm
Muestra un registro de todos los subprocesos terminados y suspendidos.
!avrf -ex [ Length ]
Muestra el registro de excepciones. El 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 los flags de CreateThread especificados por el padre. Proporcionar un identificador de subproceso mostrará información solo para ese subproceso determinado.
!avrf -tp [ ThreadID ]
Muestra el registro del grupo de subprocesos. Este registro puede contener trazas de pila para varias operaciones, como cambiar la máscara de afinidad de subproceso, cambiar la prioridad del subproceso, publicar mensajes de subproceso, inicializar COM y desinicializar COM desde dentro de la devolución de llamada del grupo de subprocesos. Proporcionar un identificador de subproceso mostrará información solo para ese subproceso determinado.
!avrf -srw [ Address | Address Length ] [ -stats ]
Muestra el registro Slim Reader/Writer (SRW). Al especificar Address 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 ser o no ser filtraciones 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 una dirección vuelca los registros de los recursos pendientes que tengan esa dirección. ResourceType puede ser uno de los siguientes:
- Montón: muestra las asignaciones del montón mediante las API de montón Win32
- Local: muestra asignaciones locales o globales
- CRT: muestra las asignaciones mediante las API de CRT
- Virtual: muestra reservas virtuales
- BSTR: Muestra las asignaciones de BSTR
- Registro: muestra las aperturas de la clave del Registro
- Power: muestra objetos de notificación de energía
- Manejo: muestra asignaciones de hilos, archivos y manejadores 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 una traza 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 de evento de interrupción. Cuando !avrf -brk se usa sin parámetros adicionales, se muestra la configuración del evento de interrupción. BreakEventType especifica el número de tipo del evento de interrupción. 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 actual de inyección de errores. 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 con errores más recientes.
!avrf -trg [ StartEnd | dll Module | all ]
Especifica que se trata de una instrucción de rango objetivo. 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. El módulo especifica el nombre de un módulo 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. Al especificar todos, se restablecen 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. El módulo especifica el nombre de un módulo que debe dirigirse o excluirse. 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 todo hace que se restablezcan todos los intervalos de destino o de exclusión. Especificar tiempo hace que se supriman todos los errores durante milisegundos de tiempo después de que se reanude la ejecución.
A continuación se muestra la salida proporcionada 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 extensión comentarios
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 parada 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 parada que se puede continuar
Este es un ejemplo de una excepción de identificador no válida que ha sido generada por la opción Detectar uso de identificadores no válidos.
En primer lugar, aparece el mensaje siguiente:
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
Tenga en cuenta 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 presentación 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 parada del Application Verifier no 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 presentación resume el problema.
Es posible que también 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 empezar a corregir los errores en el código.
Depuración de fallos en secciones críticas
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 los documentos del depurador.
Se requiere la coincidencia de símbolos con información de tipo, especialmente para ntdll.dll.
La sintaxis de esta extensión es:
!cs [-s] - listar todas las secciones críticas activas en el proceso actual.
¡cs [-s] dirección - volcar la sección crítica en esta dirección.
!cs [-s] -d dirección: para volcar la sección crítica correspondiente a DebugInfo en esta dirección.
-s volcará el seguimiento de pila de la inicialización de la sección crítica si está disponible.
Ejemplos:
Volcar información de una sección crítica usando su dirección
0:001> ! cs 0x7803B0F8
Critical section = 0x7803B0F8 (MSVCRT!__app_type+0x4)
DebugInfo = 0x6A262080
NOT LOCKED
LockSemaphore = 0x0
SpinCount = 0x0
Volcar 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
Volcar 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
Extracción de información sobre todas las secciones críticas activas en el 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.
La depuración gestiona 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 está abriendo o cerrando un identificador o cuando hace referencia a un identificador no válido. Para obtener más información sobre la extensión !htrace, consulte !htrace en los documentos del depurador.
La sintaxis del depurador de kernel para esta extensión es:
!htrace [ handle [process] ]
Si no se especifica el identificador o el identificador 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 usuario siempre muestra información sobre el proceso de depurado 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.
Volcar información 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.
Depuración de errores de montón
Extensión de depuración del verificador de montón
La extensión del verificador de montones es parte del complemento !heap (complemento del depurador de montones NT). Se puede obtener ayuda simple con el comando !heap -? o más extenso con !heap -p -? . La extensión actual no detecta por sí sola 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 page heap está habilitado y usar comandos con el prefijo !heap -p. Para obtener más información sobre la extensión !htrace, consulte !heap en la documentación del depurador.
!heap -p
Muestra las direcciones de todos los montones de páginas completas creados durante el proceso.
!heap -p -h ADDRESS-OF-HEAP
Volcado completo del montículo 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 de heap
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 !avrf -hp Length comando de 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 heap que afectaron a la dirección especificada. Para una operación de asignación, es suficiente que la Dirección esté contenida en el bloque de montón asignado. Para una operación libre, se debe proporcionar la dirección exacta del principio del bloque.
Para cada entrada del registro, se muestra la siguiente información:
- La función de cúmulo 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 de depuración típicos
Hay varios escenarios de error que se pueden encontrar. Algunos de ellos requieren bastante trabajo de detective para obtener el panorama completo.
Infracción de acceso en la página inaccesible
Esto sucede cuando se habilita el 'heap' de página completa y 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 usuarios, libre de realidad) 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 no es así, obtendrá una detención del verificador.
Si el bloque es un bloque de montón completo de página (por ejemplo, si sabe con certeza que está habilitado el montón completo de página para todas las asignaciones), puede usar "!heap –p –a ADDRESS" para determinar las características del bloque.
Si el bloque es un bloque de montón de páginas ligeras, debes averiguar la dirección de inicio del encabezado del 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 necesaria para comprender el error. En particular, 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 alinearse cuidadosamente con la llamada problemática.
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 del bloque tendrá un aspecto correcto, pero deberá observar que el primer byte después del final del encabezado (el primer byte después del valor mágico 0xDCBAXXXX) tiene una dirección diferente a 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 de kernel. Esto sucede cuando el bloque se libera (el valor de relleno es F0) y cuando se asigna el bloque, pero no se realiza ninguna solicitud para que el bloque sea cero (el valor de relleno es E0 para el montón de páginas ligeras y C0 para el montón de páginas completas). Las asignaciones sin inicializar a cero son típicas para usuarios de malloc o new. Si se produce un error (infracción de acceso) en el que se intenta leer y escribir en direcciones como F0F0F0F0, E0E0E0E0, C0C0C0C0, lo más probable es que se alcance uno de estos casos.
Una operación de lectura/escritura en F0F0F0F0 significa que se ha usado un bloque después de que se haya liberado. Desafortunadamente, necesitará algo de labor detectivesca para averiguar qué bloque causó esto. Debe obtener la traza de pila del error y luego inspeccionar el código de las funciones en la pila. Uno de ellos podría hacer una suposición incorrecta de que una asignación está activa.
Una lectura/escritura en E0E0E0E0/C0C0C0C0 significa que la aplicación no inicializó correctamente la asignación de memoria. Esto también requiere la inspección del código de las funciones en la traza 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 hacía un HeapFree en la dirección E0E0E0E0. Resultó que la prueba asignó una estructura, no la inicializó correctamente y, a continuación, llamó al destructor del objeto . Dado que un campo determinado no era nulo (tenía E0E0E0E0 en él), ejecutó delete en él.
Detalles Técnicos del Administrador de Memoria 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 va a verificar 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 page heap y es la configuración predeterminada), AppVerifier consumirá una gran cantidad de memoria virtual. Sin embargo, tiene la ventaja de que los eventos de corrupción del montón se almacenan en caché en tiempo real cuando se produce un desbordamiento o un subdesbordamiento. Recuerde que la memoria de este modo tendrá un aspecto similar al siguiente: [AppVerifier Read-Only Página del montón (4k)] [Cantidad de memoria solicitada por la aplicación en prueba] o como esta: [Cantidad de memoria solicitada por la aplicación en prueba] [AppVerifier Read-Only Página del montón (4k)].
La verificación del montón colocará una página de protección al principio o al final de la asignación dependiendo 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 los desbordamientos del búfer hacia abajo.
Al rellenar la memoria solicitada con etiquetas especiales (habilitadas desmarcando la casilla de verificación "Completo" en las propiedades del montón), AppVerifier comprobará y le avisará cuando se libere esta memoria. El principal problema al usar esta técnica es que hay algunos casos en los que solo se detectarán daños en la memoria cuando se libere 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 para usar el montón de páginas ligero es si su equipo no puede tolerar las altas restricciones de memoria del montón de páginas completo.
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 produce un problema, active el heap de página completo para investigar más a fondo.
Es posible que las aplicaciones que usan montones personalizados (un montón que omite la implementación del montón del sistema operativo) no obtengan todas las ventajas de usar page heap o incluso podrían funcionar mal cuando está habilitado.
Depuración de errores de memoria
Extensión del depurador de verificación 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. Estos incluyen VirtualAlloc, VirtualFree, MapViewOfFile y UnmapViewOfFile.
Puede usar el !avrf -vs Length comando de 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, basta con que Address esté contenido 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 denominada
- Identificador del subproceso que invocó 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)
- Tipo de protección solicitada
- 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, se lanzó 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 vuelcan comenzando por la más reciente. Por lo tanto, este registro muestra que el subproceso 0xB4 asignó una región grande en la que ha confirmado una página. Más adelante se descommitió la página y, a continuación, se publicó toda la región virtual.
Véase también
Comprobador de aplicaciones de : información general
Comprobador de aplicaciones de : pruebas de aplicaciones
Comprobador de aplicaciones: pruebas dentro del comprobador de aplicaciones
Comprobador de aplicaciones de : códigos de detención y definiciones
Comprobador de aplicaciones de : preguntas más frecuentes