偵錯記憶體流失 - DRIVER_VERIFIER_DETECTED_VIOLATION (C4): 0x62
驅動程式驗證器 會產生 錯誤檢查0xC4: 當驅動程式卸除而不先釋放其所有集區配置時,0x62參數 1 值DRIVER_VERIFIER_DETECTED_VIOLATION。 未凍結的記憶體配置(也稱為記憶體流失)是降低操作系統效能的常見原因。 這些可能會分散系統集區,並最終造成系統當機。
當您有核心調試程式連線到執行 驅動程式驗證器的測試計算機時,如果驅動程式驗證器偵測到違規,Windows 會中斷調試程式,並顯示錯誤的簡短描述。
>偵錯驅動程式卸除時的記憶體流失
- 使用 !analyze 來顯示錯誤檢查的相關信息
- 使用 !verifier 3 擴充功能命令來瞭解集區配置
- 如果您有符號,您可以在來源檔案中找出記憶體配置發生的位置
- 檢查記錄中是否有記憶體配置
- 修正記憶體流失
使用 !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:DRIVER_VERIFIER_DETECTED_VIOLATION參數 1 (Arg1) 值為 0x62,如下所示:
DRIVER_VERIFIER_DETECTED_VIOLATION (C4) Arg1 Arg2 Arg3 Arg4 導致驅動程式驗證器旗標0x62驅動程式的名稱。 未釋放的配置總數,包括分頁和非分頁集區。 驅動程式正在卸除,而不需要先釋放其集區配置。 在 Windows 8.1 中,如果驅動程式卸除而不先釋放任何已配置 IoAllocateWorkItem 的工作專案(IO_WORKITEM),也會發生此錯誤檢查。 只有在 [集區追蹤] 選項作用中時,才會發生與此參數的 Bug 檢查。 指定 集區追蹤 (驗證器/flags 0x8)。 [集區追蹤] 選項會啟用標準旗標 (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具有兩個記憶體配置,以及一個尚未正確釋放的 I/O 工作專案。 每個清單都會顯示目前配置的位址、大小、使用的集區標記,以及驅動程式程式代碼中發出配置要求所在的位址。 如果有問題的驅動程式載入符號,它也會顯示呼叫端位址旁的函式名稱。
在顯示的標記中,只有一個(位址0x8645a000的配置)是由驅動程式本身 (mdrv) 提供。 每當驅動程式驗證器驗證驅動程式呼叫 IoAllocateMdl 時,就會使用標籤 VMdl。 同樣地,每當驅動程序驗證器正在驗證驅動程式時,就會使用標籤 Vfwi 來要求使用 IoAllocateWorkItem 配置工作專案。
如果您有符號,您可以在來源檔案中找出記憶體配置發生的位置
載入驅動程式的符號時,如果這些符號包含行號資訊,您可以使用 ln CallerAddress 命令來顯示呼叫所在的行。 此輸出也會在進行配置的函式中顯示位移。
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 0x80 AddressOfPoolAllocation 來存取此記錄檔。 請注意,這會列出此特定位址記錄檔中的所有配置和釋出。 若要取消或停止記錄記錄的顯示,請使用鍵盤快捷方式: Ctrl + Break 搭配 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 驅動程式碼並報告可能的問題。 靜態驅動程式驗證器是絕佳的開發時間公用程式,可協助識別這類問題。
如需您可以使用的其他技術,包括驅動程式驗證器未涉及的案例,請參閱 尋找內核模式記憶體流失。