共用方式為


偵錯死結 - DRIVER_VERIFIER_DETECTED_VIOLATION (C4): 0x1001

當驅動程式驗證器偵測到微調鎖定階層違規時,驅動程式驗證器會產生錯誤檢查0xC4:DRIVER_VERIFIER_DETECTED_VIOLATION參數 1 值為 0x1001。

當死結偵測選項為作用中時(死結偵測是驅動程序驗證器標準選項的一部分), 驅動程序驗證器 會追蹤配置的每個微調鎖定,以及取得和釋放它的順序。 鎖定階層違規表示驅動程序驗證器偵測到至少一種情況,即在取得 LockB 之前取得並保留 LockA,而另一種情況則是在需要 LockA 之前取得並保留 LockB

重要: 每當 驅動程序驗證器 偵測到階層違規發生時,就會進行此錯誤檢查,而不是發生實際死結的情況時。 此違規會強制強制執行任何在驅動程式的各種元件之間共用的鎖定,一律應以順序取得和釋放,使兩個線程的死結變得不可能。

Windows 8.1 的新功能:當 驅動程式驗證程式 遇到此違規時,如果附加調試程式,調試程式會要求您輸入有關錯誤的資訊。 在 Windows 8 和舊版 Windows 中,此違規會導致立即檢查錯誤。

************ Verifier Detected a Potential Deadlock *************
**
** Type !deadlock in the debugger for more information.
**
*****************************************************************

*** Verifier assertion failed ***
(B)reak, (I)gnore, (W)arn only, (R)emove assert?

若要在執行 Windows 8.1 的電腦上偵錯此違規,請選擇 B (中斷),然後輸入建議的調試程式命令 (!deadlock):

kd> !deadlock
issue: 00001001 97dd800c 86858ce0 00000000 

Deadlock detected (2 locks in 2 threads):

Thread 0: A B.
Thread 1: B A.

Where:

Thread 0 = TERMINATED.
Thread 1 = c4ae2040.

Lock A =   97dd800c (MyTestDriver!AlphaLock+0x00000000) - Type 'Spinlock'.
Lock B =   97dd8008 (MyTestDriver!BravoLock+0x00000000) - Type 'Spinlock'.

!deadlock 3 命令也可以用來顯示詳細資訊,包括上次取得時堆棧:

kd> !deadlock 3
issue: 00001001 97dd800c 86858ce0 00000000 

Deadlock detected (2 locks in 2 threads):
# 

Thread 0: TERMINATED took locks in the following order:

Lock A =     97dd800c (MyTestDriver!AlphaLock+0x00000000) - Type 'Spinlock'.

    Node:    8685acd8

    Stack:   97dd65b7 MyTestDriver!SystemControlIrpWorker+0x00000027 
             97dd605a MyTestDriver!Dispatch_SystemControl+0x0000001a 
             820c4b4d nt!IovCallDriver+0x000002cc 
             81ca3772 nt!IofCallDriver+0x00000062 
             81eb165e nt!IopSynchronousServiceTail+0x0000016e 
             81eb5518 nt!IopXxxControlFile+0x000003e8 
             81eb4516 nt!NtDeviceIoControlFile+0x0000002a 
             81d27e17 nt!KiSystemServicePostCall+0x00000000 

Lock B =     97dd8008 (MyTestDriver!BravoLock+0x00000000) - Type 'Spinlock'.

    Node:    86833578

    Stack:   97dd65c5 MyTestDriver!SystemControlIrpWorker+0x00000a4a 
             97dd605a MyTestDriver!Dispatch_SystemControl+0x0000001a 
             820c4b4d nt!IovCallDriver+0x000002cc 
             81ca3772 nt!IofCallDriver+0x00000062 
             81eb165e nt!IopSynchronousServiceTail+0x0000016e 
             81eb5518 nt!IopXxxControlFile+0x000003e8 
             81eb4516 nt!NtDeviceIoControlFile+0x0000002a 
             81d27e17 nt!KiSystemServicePostCall+0x00000000
# 

Thread 1: c4ae2040 (ThreadEntry = 86833a08) took locks in the following order:

Lock B =     97dd8008 (MyTestDriver!BravoLock+0x00000000) - Type 'Spinlock'.

    Node:    86858ce0

    Stack:   97dd65ef MyTestDriver!DeviceControlIrpWorker+0x0000005f 
             97dd605a MyTestDriver!Dispatch_DeviceControl+0x0000001a 
             820c4b4d nt!IovCallDriver+0x000002cc 
             81ca3772 nt!IofCallDriver+0x00000062 
             81eb165e nt!IopSynchronousServiceTail+0x0000016e 
             81eb5518 nt!IopXxxControlFile+0x000003e8 
             81eb4516 nt!NtDeviceIoControlFile+0x0000002a 
             81d27e17 nt!KiSystemServicePostCall+0x00000000 

Lock A =     97dd800c (MyTestDriver!AlphaLock+0x00000000) - Type 'Spinlock'.

    Stack:   << Current stack trace - use kb to display it >>

調試程式會建議使用 kb (Display Stack Backtrace) 命令來顯示目前的堆疊追蹤。

kd> kb
ChildEBP RetAddr  Args to Child              
89b2cac4 820da328 97dd800c 86858ce0 00000000 nt!VfReportIssueWithOptions+0x86
89b2caf4 820d92a2 00000001 00000000 97dd65fd nt!ViDeadlockAnalyze+0x1d1
89b2cb7c 820d424e 86858ce0 00000000 97dd65fd nt!VfDeadlockAcquireResource+0x2fd
89b2cb9c 97dd65fd 00007780 89b2cbbc 97dd605a nt!VerifierKfAcquireSpinLock+0x8c
89b2cba8 97dd605a 9a9e7780 88d08f48 00000000 MyTestDriver!DeviceControlIrpWorker+0x54a
89b2cbbc 820c4b4d 9a9e7780 88d08f48 820c4881 MyTestDriver!Dispatch_DeviceControl+0x1a
(Inline) -------- -------- -------- -------- nt!IopfCallDriver+0x47
89b2cbe0 81ca3772 81eb165e b3c9ff80 88d08f48 nt!IovCallDriver+0x2cc
89b2cbf4 81eb165e 88d08fdc 88d08f48 00000000 nt!IofCallDriver+0x62

調試程式輸出顯示有問題的驅動程式在取得鎖定 B 之前先取得鎖定 A,再取得鎖定 B,並嘗試在另一個線程上取得鎖定 A 來違反此規則。 請注意,第一個線程 (Thread 0) 已終止,因此在載入驅動程式映像之後,這兩個鎖定的擷取和後續釋放會在某個時間點發生。

載入測試驅動程式的適當符號時,調試程式會顯示當時取得鎖定的函式。 在此範例中,鎖定 A 和 Lock B 都會在同一個函式中取得。 在 Thread 0 中,它們都是在 SystemControlIrpWorker取得。 在 Thread 1 中,這兩者都是在 DeviceControlIrpWorker 中取得的(如來自 !deadlock 3 的 Lock B 輸出和目前的堆棧輸出 #kb 所示。

此時,檢閱每個函式的原始碼應該會顯示程式代碼路徑存在,其中可以依此類順序取得鎖定。

MyTestDriver! AlphaLockMyTestDriver!BravoLock 是驅動程式中全域可用的物件:

include "MyTestDriverHeader.h"

// Locks used to control access to various objects
extern KSPIN_LOCK AlphaLock;
extern KSPIN_LOCK BravoLock;

在 SystemControlIrpWorker 函式內部,有一個路徑,其中在取得 BravoLock (Lock B) 時,會取得並保留 AlphaLock (!死結輸出中的 Lock A)。 值得注意的是,鎖定會以取得鎖定的反向順序正確釋放。 (下列程式代碼會大量編輯,只顯示產生此案例所需的元素。

NTSTATUS SystemControlIrpWorker(_In_ PIRP Irp)
{
    KIRQL IrqlAlpha;
    KIRQL IrqlBravo;
    // <<Other local variable declarations removed>>

    // <<Various lines of code not shown>>

    KeAcquireSpinLock (&AlphaLock, &IrqlAlpha);

    // <<Various lines of code not shown>>

    KeAcquireSpinLock (&BravoLock, &IrqlBravo);

    // <<Various lines of code not shown>>

    KeReleaseSpinLock (&BravoLock, IrqlBravo);
    KeReleaseSpinLock (&AlphaLock, IrqlAlpha);

    // <<Various lines of code not shown>>
}

如果您檢閱下列 DeviceControlIrpWorker 範例函式,您可以看到可以反向取得鎖定。 也就是說,在嘗試收購 AlphaLock 時,可以取得並保留 BravoLock。 下列範例已簡化,但會顯示可能發生違規的路徑。

NTSTATUS DeviceControlIrpWorker(_In_ PIRP Irp, 
                                _In_ BOOLEAN bSomeCondition)
{
    KIRQL IrqlAlpha;
    KIRQL IrqlBravo;
    // <<Other local variable declarations removed>>

    if (bSomeCondition == FALSE)
    {
        //
        // Note that if bSomeCondition is FALSE, then AlphaLock is acquired here
        // If bSomeCondition is TRUE, it is not needed to be acquired right now
        //
        KeAcquireSpinLock (&AlphaLock, &IrqlAlpha);
    }

    // <<Various lines of code not shown>>

    KeAcquireSpinLock (&BravoLock, &IrqlBravo);

    // <<Various lines of code not shown>>

    if (bSomeCondition == TRUE)
    { 
        //
        // Need to acquire AlphaLock here for upcoming code logic
        //
        KeAcquireSpinLock (&AlphaLock, &IrqlAlpha);

        // <<Various lines of code not shown>>

        KeReleaseSpinLock (&AlphaLock, IrqlAlpha);
    }

    // <<Various lines of code not shown>>

    KeReleaseSpinLock (&BravoLock, IrqlBravo);

    if (bSomeCondition == FALSE)
    {
        //
        // Release the AlphaLock, which was acquired much earlier
        //
        KeReleaseSpinLock (&AlphaLock, IrqlAlpha);
    }

    // <<Various lines of code not shown>>
}

若要修正此潛在違規問題,正確的作法是確保每當司機嘗試取得AlphaLock時,就會檢查並確認未保留BravoLock。 最簡單的修正方式可能是只要釋放 BravoLock,並在取得 AlphaLock 後立即重新取得它。 但是,如果 BravoLock 保護的數據在等待 AlphaLock 和重新取得 BravoLock 時不會變更,則可能需要更顯著的程式碼變更。

如需微調鎖定和其他同步處理技術的詳細資訊,請參閱 微調鎖定

微調鎖定

錯誤檢查0xC4:DRIVER_VERIFIER_DETECTED_VIOLATION

!僵局