Partilhar via


Depurando os vazamentos de memória - DRIVER_VERIFIER_DETECTED_VIOLATION (C4): 0x62

O Verificador de Driver gera 0xC4 de Verificação de Bugs: DRIVER_VERIFIER_DETECTED_VIOLATION com um valor de parâmetro 1 de 0x62 quando um driver é descarregado sem primeiro liberar todas as suas alocações de pool. As alocações de memória não liberadas (também chamadas de vazamentos de memória) são uma causa comum de desempenho reduzido do sistema operacional. Isso pode fragmentar os pools do sistema e, eventualmente, causar falhas no sistema.

Quando você tem um depurador de kernel conectado a um computador de teste que executa o Verificador de Driver, se o Verificador de Driver detectar uma violação, o Windows interromperá o depurador e exibirá uma breve descrição do erro.

>Depuração de vazamentos de memória no descarregamento do driver

Use !analyze para exibir informações sobre a verificação de bugs

Assim como acontece com qualquer verificação de bug que ocorre, depois de ter o controle do depurador, a melhor primeira etapa é executar o comando !analyze -v .

kd> !analyze -v
Connected to Windows 8 9600 x86 compatible target
Loading Kernel Symbols
.................................................................................
Loading User Symbols
.......................
Loading unloaded module list
........
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

DRIVER_VERIFIER_DETECTED_VIOLATION (c4)
A device driver attempting to corrupt the system has been caught.  This is
because the driver was specified in the registry as being suspect (by the
administrator) and the kernel has enabled substantial checking of this driver.
If the driver attempts to corrupt the system, bugchecks 0xC4, 0xC1 and 0xA will
be among the most commonly seen crashes.
Arguments:
Arg1: 00000062, A driver has forgotten to free its pool allocations prior to unloading.
Arg2: 9707712c, name of the driver having the issue.
Arg3: 9c1faf70, verifier internal structure with driver information.
Arg4: 00000003, total # of (paged+nonpaged) allocations that weren't freed.
    Type !verifier 3 drivername.sys for info on the allocations
    that were leaked that caused the bugcheck.

Uma verificação de bug 0xC4: DRIVER_VERIFIER_DETECTED_VIOLATION com um valor de parâmetro 1 (Arg1) de 0x62 é descrita da seguinte forma:

DRIVER_VERIFIER_DETECTED_VIOLATION (C4) Arg1 Arg2 Arg3 Arg4 Cause Driver Verifier sinaliza 0x62 Nome do driver. Reservado Número total de alocações que não foram liberadas, incluindo pool paginado e não paginado. O driver está descarregando sem primeiro liberar suas alocações de pool. No Windows 8.1, essa verificação de bug também ocorrerá se o driver for descarregado sem primeiro liberar nenhum item de trabalho (IO_WORKITEM) alocado com IoAllocateWorkItem. Uma verificação de bug com esse parâmetro ocorre somente quando a opção Rastreamento de pool está ativa. Especifique o Rastreamento de Pool (verificador /flags 0x8). A opção Rastreamento de pool é habilitada com sinalizadores padrão (verificador /padrão ).

Use o comando de extensão !verifier 3 para saber mais sobre as alocações de pool

Para essa verificação de bug específica, as informações fornecidas no parâmetro 4 (Arg4) são as mais importantes. Arg4 mostra o número de alocações que não foram liberadas. A saída do comando !analyze também mostra o comando de extensão do depurador !verifier que você pode usar para exibir quais foram essas alocações. A saída completa do comando MyDriver.sys !verifier 3 é mostrada no exemplo a seguir:

kd> !verifier 3 Mydriver.sys

Verify Flags Level 0x000209bb

  STANDARD FLAGS:
    [X] (0x00000000) Automatic Checks
    [X] (0x00000001) Special pool
    [X] (0x00000002) Force IRQL checking
    [X] (0x00000008) Pool tracking
    [X] (0x00000010) I/O verification
    [X] (0x00000020) Deadlock detection
    [X] (0x00000080) DMA checking
    [X] (0x00000100) Security checks
    [X] (0x00000800) Miscellaneous checks
    [X] (0x00020000) DDI compliance checking

  ADDITIONAL FLAGS:
    [ ] (0x00000004) Randomized low resources simulation
    [ ] (0x00000200) Force pending I/O requests
    [ ] (0x00000400) IRP logging
    [ ] (0x00002000) Invariant MDL checking for stack
    [ ] (0x00004000) Invariant MDL checking for driver
    [ ] (0x00008000) Power framework delay fuzzing
    [ ] (0x00040000) Systematic low resources simulation
    [ ] (0x00080000) DDI compliance checking (additional)
    [ ] (0x00200000) NDIS/WIFI verification
    [ ] (0x00800000) Kernel synchronization delay fuzzing
    [ ] (0x01000000) VM switch verification

    [X] Indicates flag is enabled


Summary of All Verifier Statistics

  RaiseIrqls           0x0
  AcquireSpinLocks     0x0
  Synch Executions     0x0
  Trims                0x0

  Pool Allocations Attempted             0x2db1a
  Pool Allocations Succeeded             0x2db1a
  Pool Allocations Succeeded SpecialPool 0x2db1a
  Pool Allocations With NO TAG           0x0
  Pool Allocations Failed                0x0

  Current paged pool allocations         0x0 for 00000000 bytes
  Peak paged pool allocations            0x0 for 00000000 bytes
  Current nonpaged pool allocations      0x3 for 00001058 bytes
  Peak nonpaged pool allocations         0x13 for 0004A4A0 bytes

## Driver Verification List


  MODULE: 0x84226b28 MyDriver.sys (Loaded)

    Pool Allocation Statistics: ( NonPagedPool / PagedPool )

      Current Pool Allocations: ( 0x00000003 / 0x00000000 )
      Current Pool Bytes:       ( 0x00001058 / 0x00000000 )
      Peak Pool Allocations:    ( 0x00000013 / 0x00000000 )
      Peak Pool Bytes:          ( 0x0004A4A0 / 0x00000000 )
      Contiguous Memory Bytes:       0x00000000
      Peak Contiguous Memory Bytes:  0x00000000

    Pool Allocations:

      Address     Length      Tag   Caller    
      ----------  ----------  ----  ----------
      0x982a8fe0  0x00000020  VMdl  0x9a3bf6ac  MyDriver!DeviceControlDispatch
      0x8645a000  0x00001008  mdrv  0x9a3bf687  MyDriver!DeviceControlDispatch
      0x9a836fd0  0x00000030  Vfwi  0x9a3bf6ed  MyDriver!GetNecessaryObjects

Por exemplo, o driver, MyDriver.sys, tem duas alocações de memória e um item de trabalho de E/S que não foram liberados corretamente. Cada listagem mostra o endereço da alocação atual, o tamanho, a marca de pool usada e o endereço no código do driver em que a solicitação de alocação foi feita. Se os símbolos forem carregados para o driver em questão, ele também mostrará o nome da função ao lado do endereço do chamador.

Das tags exibidas, apenas uma (para a alocação no endereço 0x8645a000) foi fornecida pelo próprio driver (mdrv). A marca VMdl é usada sempre que um driver que está sendo verificado pelo Verificador de Driver faz chamadas IoAllocateMdl. Da mesma forma, a marca Vfwi é usada sempre que um driver que está sendo verificado pelo Verificador de Driver faz uma solicitação para alocar um item de trabalho usando IoAllocateWorkItem.

Se você tiver símbolos, poderá localizar onde nos arquivos de origem ocorreram as alocações de memória

Quando os símbolos são carregados para o driver, se esses símbolos contiverem as informações do número da linha, você poderá usar o comando ln CallerAddress para mostrar a linha em que a chamada foi feita. Essa saída também mostrará o deslocamento na função que fez a alocação.

kd> ln 0x9a3bf6ac  
d:\coding\wdmdrivers\mydriver\handleioctl.c(50)+0x15
(9a3bf660)   MyDriver!DeviceControlDispatch+0x4c   |  (9a3bf6d0)   MyDriver!DeviceControlDispatch

kd> ln 0x9a3bf687  
d:\coding\wdmdrivers\mydriver\handleioctl.c(38)+0x12
(9a3bf660)   MyDriver!DeviceControlDispatch+0x27   |  (9a3bf6d0)   MyDriver!DeviceControlDispatch

kd> ln 0x9a3bf6ed  
d:\coding\wdmdrivers\mydriver\handleioctl.c(72)+0xa
(9a3bf6d0)   MyDriver!GetNecessaryObjects+0x1d   |  (9a3bf71c)   MyDriver!GetNecessaryObjects

Examinar o log para alocações de memória

O Verificador de Driver também mantém um log circular de todas as alocações de memória feitas no espaço do kernel quando o rastreamento de pool está habilitado. Por padrão, as alocações mais recentes de 65.536 (0x10000) são mantidas. À medida que uma nova alocação é feita, a alocação mais antiga no log é substituída. Se as alocações foram feitas recentemente antes da falha, pode ser possível obter informações adicionais sobre a alocação do que as mostradas acima, especificamente o endereço do thread e os quadros da pilha do kernel no momento da alocação.

Esse log pode ser acessado usando o comando !verifier 0x80 AddressOfPoolAllocation. Observe que isso listará todas as alocações e liberações no log para esse endereço específico. Para cancelar ou interromper a exibição do histórico de log, use os atalhos de teclado: Ctrl + Break com WinDbg e Ctrl + C com KD.

kd> !verifier 0x80 0x982a8fe0

Log of recent kernel pool Allocate and Free operations:

There are up to 0x10000 entries in the log.

Parsing 0x00010000 log entries, searching for address 0x982a8fe0.

# 

Pool block 982a8fe0, Size 00000020, Thread 9c158bc0
81b250cd nt!IovAllocateMdl+0x3d
8060e41d VerifierExt!IoAllocateMdl_internal_wrapper+0x35
81b29388 nt!VerifierIoAllocateMdl+0x22
9a3bf6ac MyDriver!DeviceControlDispatch+0x4c
9a3bf611 MyDriver!NonPNPIRPDispatch0x51
9a3bf05a MyDriver!AllIRPDispatch+0x1a
80611710 VerifierExt!xdv_IRP_MJ_DEVICE_CONTROL_wrapper+0xd0
81b3b635 nt!ViGenericDispatchHandler+0x2d
81b3b784 nt!ViGenericDeviceControl+0x18
81b24b4d nt!IovCallDriver+0x2cc
81703772 nt!IofCallDriver+0x62
8191165e nt!IopSynchronousServiceTail+0x16e
81915518 nt!IopXxxControlFile+0x3e8

kd> !verifier 0x80 0x8645a000

Log of recent kernel pool Allocate and Free operations:

There are up to 0x10000 entries in the log.

Parsing 0x00010000 log entries, searching for address 0x8645a000.

# 

Pool block 8645a000, Size 00001000, Thread 9c158bc0
8060ee4f VerifierExt!ExAllocatePoolWithTagPriority_internal_wrapper+0x5b
81b2619e nt!VerifierExAllocatePoolWithTag+0x24
9a3bf687 MyDriver!DeviceControlDispatch+0x27
9a3bf611 MyDriver!NonPNPIRPDispatch0x51
9a3bf05a MyDriver!AllIRPDispatch+0x1a
80611710 VerifierExt!xdv_IRP_MJ_DEVICE_CONTROL_wrapper+0xd0
81b3b635 nt!ViGenericDispatchHandler+0x2d
81b3b784 nt!ViGenericDeviceControl+0x18
81b24b4d nt!IovCallDriver+0x2cc
81703772 nt!IofCallDriver+0x62
8191165e nt!IopSynchronousServiceTail+0x16e
81915518 nt!IopXxxControlFile+0x3e8
81914516 nt!NtDeviceIoControlFile+0x2a

kd> !verifier 0x80 0x9a836fd0  

Log of recent kernel pool Allocate and Free operations:

There are up to 0x10000 entries in the log.

Parsing 0x00010000 log entries, searching for address 0x9a836fd0.

# 

Pool block 9a836fd0, Size 00000030, Thread 88758740
8151713d nt!IovAllocateWorkItem+0x1b
84a133d9 VerifierExt!IoAllocateWorkItem_internal_wrapper+0x29
8151b3a7 nt!VerifierIoAllocateWorkItem+0x16
9a3bf6ed MyDriver!GetNecessaryObjects+0x1d
9a3bf620 MyDriver!NonPNPIRPDispatch0x51
9a3bf05a MyDriver!AllIRPDispatch+0x1a
84a16710 VerifierExt!xdv_IRP_MJ_DEVICE_CONTROL_wrapper+0xd0
8152d635 nt!ViGenericDispatchHandler+0x2d
8152d784 nt!ViGenericDeviceControl+0x18
81516b4d nt!IovCallDriver+0x2cc
810f5772 nt!IofCallDriver+0x62
8130365e nt!IopSynchronousServiceTail+0x16e
81307518 nt!IopXxxControlFile+0x3e8

Corrigindo vazamentos de memória

Essa verificação de bugs do Verificador de Driver foi projetada para impedir que o driver vaze memória do kernel. Em cada caso, a correção adequada é identificar todos os caminhos de código existentes em que os objetos alocados não são liberados e garantir que eles sejam liberados corretamente.

O Verificador de Driver Estático é uma ferramenta que verifica o código-fonte do driver do Windows e relata possíveis problemas simulando o exercício de vários caminhos de código. O Verificador de Driver Estático é um excelente utilitário de tempo de desenvolvimento para ajudar a identificar esses tipos de problemas.

Para outras técnicas que você pode usar, incluindo cenários em que o Verificador de Driver não está envolvido, consulte Localizando um vazamento de memória no modo kernel.

Localizando um vazamento de memória no modo kernel

Verificador de driver estático

Depuração do Windows

Manipulando uma verificação de bugs quando o Verificador de driver está habilitado