メモリ リークのデバッグ - DRIVER_VERIFIER_DETECTED_VIOLATION(C4):0x62

ドライバー検証ツール は、最初にすべてのプール割り当てを解放せずにドライバーがアンロードするときに、パラメーター 1 の値 0x62 を持つ バグ チェック 0xC4 DRIVER_VERIFIER_DETECTED_VIOLATION を生成します。 頻度の低いメモリ割り当て (メモリ リークとも呼ばれます) は、オペレーティング システムのパフォーマンス低下の一般的な原因です。 これらはシステム プールを断片化し、最終的にシステム クラッシュの原因となる可能性があります。

ドライバーの検証ツールを実行しているテスト コンピューターにカーネル デバッガーが接続されていて、 ドライバーの検証ツールが違反を検出すると、Windows はデバッガーを中断し、エラーの簡単な説明を表示します。

>ドライバーのアンロード時のメモリ リークのデバッグ

!analyze を使用してバグ チェックに関する情報を表示する

発生するバグ チェックと同様に、デバッガーを制御したら、最初に !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.

バグ チェック 0xC4: パラメーター 1 (Arg1) の値が0x62のDRIVER_VERIFIER_DETECTED_VIOLATIONは次のように記述されています。

DRIVER_VERIFIER_DETECTED_VIOLATION (C4) Arg1 Arg2 Arg3 Arg4 原因ドライバー検証ツール フラグ 0x62ドライバーの名前。 ページ プールと非ページ プールの両方を含む、解放されなかった予約割り当て総数 。 ドライバーは、最初にプールの割り当てを解放せずにアンロードしています。 Windows 8.1 では、このバグチェックは、IoAllocateWorkItem で割り当てた作業項目 (IO_WORKITEM) を最初に解放せずにドライバーがアンロードされた 場合にも発生します。 このパラメーターでチェックバグは、プール追跡 オプションがアクティブな場合 にのみ発生します。 プールの追跡 (検証ツール /flags 0x8) を指定します。 Pool Tracking オプションは、Standard Flags (verifier /standard ) で有効になっています。

!verifier 3 拡張機能コマンドを使用して、プールの割り当てについて調べる

この特定のバグ チェックでは、パラメーター 4 (Arg4) で提供される情報が最も重要です。 Arg4 には、解放されなかった割り当ての数が表示されます。 !analyze コマンドの出力には、割り当てが何であったかを表示することができる !verifier デバッガー拡張コマンドも表示されます。 !verifier 3 MyDriver.sys コマンドの 完全な出力を次の例に示します。

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

この例では、ドライバー MyDriver.sysには、適切に解放されていない 2 つのメモリ割り当てと、1 つの I/O 作業項目があります。 各一覧には、現在の割り当てのアドレス、サイズ、使用されるプール タグ、および割り当ての要求が行われたドライバー コードのアドレスが表示されます。 対象のドライバーのシンボルが読み込まれている場合は、呼び出し元のアドレスの横に関数の名前も表示されます。

表示されたタグのうち、ドライバー自体 (mdrv) によって提供された (アドレス 0x8645a000での割り当てに対して) 1 つだけです。 ドライバー検証ツールによって検証されるドライバーが IoAllocateMdl を呼び出 すたびに、タグ VMdl が使用されます。 同様に、ドライバー検証ツールによって検証されるドライバーが IoAllocateWorkItem を使用して作業項目を割り当てる要求を行うたびに、タグ Vfwi が使用されます。

シンボルがある場合は、ソース ファイル内のメモリ割り当てが発生した場所を見つけることができます

ドライバーにシンボルが読み込まれるときに、それらのシンボルに行番号情報が含まれている場合は、 lnCallerAddress コマンドを使用して、呼び出しが行われた行を表示できます。 この出力には、割り当てを行った関数のオフセットも表示されます。

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

メモリ割り当てについてログを調べる

ドライバー検証ツールでは、プールの追跡が有効になっているときには、カーネル空間で行われたすべてのメモリ割り当ての循環ログも保持されます。 既定では、最新の 65,536 (0x10000) の割り当てが保持されます。 新しい割り当てが行われると、ログ内の最も古い割り当てが上書きされます。 割り当てがクラッシュ前に最近行われた場合は、上記よりも割り当てに関する追加情報 (特に、割り当て時のカーネル スタックのスレッド アドレスとフレーム) を取得できる可能性があります。

このログには、コマンド !verifier 0x80AddressOfPoolAllocationを使用してアクセスできます。 これにより、この特定のアドレスのすべての割り当てと解放がログに一覧表示されることに注意してください。 ログ履歴の表示をキャンセルまたは停止するには、キーボード ショートカット (Ctrl + Break with WinDbg)、 Ctrl + C (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

メモリ リークの修正

このドライバー検証ツールのバグ チェックは、ドライバーがカーネル メモリをリークしないように設計されています。 いずれの場合も、適切な修正は、割り当てられたオブジェクトが解放されていない既存のコード パスを特定し、それらが適切に解放されていることを確認することです。

静的ドライバー検証ツール は、Windows ドライバーのソース コードをスキャンし、さまざまなコード パスの実行をシミュレートすることによって、考えられる問題を報告するツールです。 静的ドライバー検証ツールは、このような問題を特定するのに役立つ優れた開発時ユーティリティです。

ドライバー検証ツールが関係しないシナリオなど、使用できるその他の手法については、「カーネル モード メモリ リーク の検出」を参照してください

カーネルモード メモリ リークの検出

静的ドライバー検証ツール

Windows のデバッグ

ドライバーの検証ツールが有効な場合のバグ チェックの処理