다음을 통해 공유


디버깅 메모리 누수 - DRIVER_VERIFIER_DETECTED_VIOLATION(C4): 0x62

드라이버 검증 도구 는 버그 검사 0xC4 생성합니다 . 먼저 모든 풀 할당을 해제하지 않고 드라이버가 언로드할 때 매개 변수 1 값이 0x62 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)을 해제하지 않고 드라이버가 언로드된 경우에도 이 버그 검사가 수행됩니다. 이 매개 변수를 사용한 버그 검사는 풀 추적 옵션이 활성화된 경우에만 발생합니다. 풀 추적(검증 도구 /플래그 0x8)을 지정합니다. 풀 추적 옵션은 표준 플래그(검증 도구 /표준 )로 사용하도록 설정됩니다.

!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 작업 항목이 있습니다. 각 목록에는 현재 할당의 주소, 크기, 사용된 풀 태그 및 할당 요청이 만들어진 드라이버 코드의 주소가 표시됩니다. 해당 드라이버에 대한 기호가 로드되면 호출자 주소 옆에 함수 이름도 표시됩니다.

표시된 태그 중 드라이버 자체(mdrv)에서 하나(0x8645a000 주소 할당용)만 제공되었습니다. 태그 VMdl은 드라이버 검증 도구에서 확인되는 드라이버가 IoAllocateMdl을 호출할 때마다 사용됩니다. 마찬가지로 드라이버 검증 도구에서 확인 중인 드라이버가 IoAllocateWorkItem을 사용하여 작업 항목을 할당하도록 요청할 때마다 Vfwi 태그가 사용됩니다.

기호가 있는 경우 원본 파일에서 메모리 할당이 발생한 위치를 찾을 수 있습니다.

드라이버에 대한 기호를 로드할 때 해당 기호에 줄 번호 정보가 포함된 경우 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 with WinDbg 및 Ctrl + C with 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 디버깅 도구

드라이버 검증 도구가 사용하도록 설정된 경우 버그 검사 처리