2016-05-17 110 views
5

我正在爲Windows 7 32位編寫設備驅動程序。我正在使用WDK版本7600.16385.1。到目前爲止,事情進展順利,但prefast總是告訴我,我搞亂了IRQL級別。特別是當我嘗試鎖定/解鎖共享緩衝區時。Prefast註釋修復IRQL級別警告

我有一個代表,像這樣的緩衝結構:

typedef struct _PORT_BUFFER { 

    WDFMEMORY mMemory; 
    PUCHAR  pucBuff; 
    ULONG  ulSizeMax; 
    ULONG  ulSizeCurr; 
    ULONG  ulAdd; 
    ULONG  ulRemove; 
    ULONG  ulLost; 
    WDFREQUEST rPending; 
    BOOLEAN  bDMAing; 

    WDFSPINLOCK slLock; 

} PORT_BUFFER, *PPORT_BUFFER; 

我有兩個功能,可以鎖定和解鎖說緩衝區:

VOID PLxBufferLock(PPORT_BUFFER ppbBuff){ 

    WdfSpinLockAcquire(ppbBuff->slLock); 

} 

VOID PLxBufferUnlock(PPORT_BUFFER ppbBuff){ 

    WdfSpinLockRelease(ppbBuff->slLock); 

} 

當我編譯我的司機,PREfast的告訴我:

warning 28167 : The function 'PLxBufferLock' changes the IRQL and does not restore the IRQL before it exits. It should be annotated to reflect the change or the IRQL should be restored. IRQL was last set to 2 at line 57. 

warning 28167 : The function 'PLxBufferUnlock' changes the IRQL and does not restore the IRQL before it exits. It should be annotated to reflect the change or the IRQL should be restored. IRQL was last set at line 63. 

所以,我看着WdfSpinLockAcquire和WdfSpinLockRelease如何AR e定義:

__drv_raisesIRQL(DISPATCH_LEVEL) 
__drv_maxIRQL(DISPATCH_LEVEL) 
VOID 
FORCEINLINE 
WdfSpinLockAcquire(
    __in 
    __drv_savesIRQL 
    __drv_neverHold(SpinLockObj) 
    __drv_acquiresResource(SpinLockObj) 
    WDFSPINLOCK SpinLock 
    ) 
{ 
    ((PFN_WDFSPINLOCKACQUIRE) WdfFunctions[WdfSpinLockAcquireTableIndex])(WdfDriverGlobals, SpinLock); 
} 

__drv_maxIRQL(DISPATCH_LEVEL) 
__drv_minIRQL(DISPATCH_LEVEL) 
VOID 
FORCEINLINE 
WdfSpinLockRelease(
    __in 
    __drv_restoresIRQL 
    __drv_mustHold(SpinLockObj) 
    __drv_releasesResource(SpinLockObj) 
    WDFSPINLOCK SpinLock 
    ) 
{ 
    ((PFN_WDFSPINLOCKRELEASE) WdfFunctions[WdfSpinLockReleaseTableIndex])(WdfDriverGlobals, SpinLock); 
} 

看起來很直截了當。所以我改變了我的功能看起來是一樣的:

__drv_raisesIRQL(DISPATCH_LEVEL) 
__drv_maxIRQL(DISPATCH_LEVEL) 
VOID PLxBufferLock(
    __in 
    __drv_savesIRQL 
    __drv_neverHold(ppbBuff) 
    __drv_acquiresResource(ppbBuff) 
    PPORT_BUFFER ppbBuff); 

__drv_maxIRQL(DISPATCH_LEVEL) 
__drv_minIRQL(DISPATCH_LEVEL) 
VOID PLxBufferUnlock(
    __in 
    __drv_restoresIRQL 
    __drv_mustHold(ppbBuff) 
    __drv_releasesResource(ppbBuff) 
    PPORT_BUFFER ppbBuff); 

然後,我從兩個警告,很多很多的警告去泄漏ppbBuff,但仍不能正確還原IRQL級別:

warning 28103 : Leaking the ppbBuff stored in 'ppbBuff'. 
warning 28104 : The ppbBuff that should have been acquired before function exit was not acquired. 
warning 28107 : The ppbBuff '&pdepPort->pbRead' must be held when calling 'PLxBufferUnlock'. 
warning 28107 : The ppbBuff '&pdepPort->pbWrite' must be held when calling 'PLxBufferUnlock'. 
warning 28107 : The ppbBuff '&pdepExtPort->pbRead' must be held when calling 'PLxBufferUnlock'. 
warning 28107 : The ppbBuff '&pdepExtPort->pbRead' must be held when calling 'PLxBufferUnlock'. 
warning 28107 : The ppbBuff '&pdepExtPort->pbWrite' must be held when calling 'PLxBufferUnlock'. 
warning 28157 : The IRQL in 'ppbBuff' was never restored. 
warning 28158 : No IRQL was saved into 'ppbBuff'. 
warning 28166 : The function 'PLxInitEvtPortCleanup' does not restore the IRQL to the value that was current at function entry and is required to do so. IRQL was last set at line 320. 
warning 28166 : The function 'PLxReadEvt' does not restore the IRQL to the value that was current at function entry and is required to do so. IRQL was last set at line 51. 
warning 28166 : The function 'PLxReadEvtTimer' does not restore the IRQL to the value that was current at function entry and is required to do so. IRQL was last set at line 104. 
warning 28166 : The function 'PLxWriteEvt' does not restore the IRQL to the value that was current at function entry and is required to do so. IRQL was last set at line 60. 

我用的緩衝區而且我沒有在任何地方檢查錯誤,所以我認爲我正確鎖定了。在這種情況下,任何人都知道如何安撫prefast?謝謝!

編輯:

在此處,我使用了鎖定功能的示例:

VOID PLxInitEvtPortCleanup(WDFFILEOBJECT foFileObject){ 

    PDEVICE_EXTENSION_PORT pdepPort = NULL; 
    PDEVICE_EXTENSION_CARD pdecCard = NULL; 
    GSCSIO4BXSYNC_PORT_CONFIGURATION pcPortConfig = { 0 }; 
    WDFREQUEST rRequest = NULL; 

    pdepPort = PLxGetDeviceContextPort(WdfFileObjectGetDevice(foFileObject)); 

    pdecCard = PLxGetDeviceContextCard(pdepPort->dDeviceCard); 

    pcPortConfig.bEnable = FALSE; 
    pcPortConfig.bRxEnable = FALSE; 
    pcPortConfig.bTxEnable = FALSE; 
    pcPortConfig.ulClockFrequency = 0; 
    pcPortConfig.eptcdTxClockDirection = GSCSIO4BXSYNC_ESTCD_INPUT; 

    PLxSioConfigPortSet(pdecCard,pdepPort->ulPortNumber,&pcPortConfig); 

    PLxBufferLock(&pdepPort->pbRead); 

    rRequest = PLxBufferClearPendingRequest(&pdepPort->pbRead); 

    PLxBufferUnlock(&pdepPort->pbRead); 

    if (rRequest) WdfRequestComplete(rRequest,STATUS_CANCELLED); 

    PLxBufferLock(&pdepPort->pbWrite); 

    rRequest = PLxBufferClearPendingRequest(&pdepPort->pbWrite); 

    PLxBufferUnlock(&pdepPort->pbWrite); 

    if (rRequest) WdfRequestComplete(rRequest,STATUS_CANCELLED); 

} 

我鎖定緩衝液,除去任何掛起的請求,解鎖緩衝器和完成該請求。 Prefast告訴我,我沒有正確恢復IRQL級別。當我註釋掉鎖定/清除/解鎖/完整代碼時,prefast很快樂。

編輯:

我升級到VS2015和WDK10 + SDK10。我已經添加了由M'hand BOUGHIAS建議註釋:

_Acquires_lock_(ppbBuff->slLock) 
_Requires_lock_not_held_(ppbBuff->slLock) 
_IRQL_saves_ 
VOID PLxBufferLock(PPORT_BUFFER ppbBuff){ 

    WdfSpinLockAcquire(ppbBuff->slLock); 

} 

_Releases_lock_(ppbBuff->slLock) 
_Requires_lock_held_(ppbBuff->slLock) 
_IRQL_restores_ 
VOID PLxBufferUnlock(PPORT_BUFFER ppbBuff){ 

    WdfSpinLockRelease(ppbBuff->slLock); 

} 

現在我得到以下幾點:

warning C28158: No IRQL was saved into 'return'. 
warning C28167: The function 'PLxBufferLock' changes the IRQL and does not restore the IRQL before it exits. It should be annotated to reflect the change or the IRQL should be restored. 
warning C28157: The IRQL in 'return' was never restored. 

我注意到,其中定義爲任何的_Acquires_lock_和_Requires_lock_not_held_所以我看着他們並注意到他們需要_PREFAST_被定義爲工作。所以我將_PREFAST_添加到我的預處理器定義中。現在我得到了一堆鏈接錯誤,但沒有更多的prefast錯誤!

error LNK2005: __Lock_kind_mutex_ already defined in Buffer.obj 
error LNK2005: __Lock_kind_event_ already defined in Buffer.obj 
error LNK2005: __Lock_kind_semaphore_ already defined in Buffer.obj 
error LNK2005: __Lock_kind_spin_lock_ already defined in Buffer.obj 
error LNK2005: __Lock_kind_critical_section_ already defined in Buffer.obj 
error LNK2001: unresolved external symbol __Prefast_unreferenced_parameter_impl_ 

我想我在把我的項目轉換到VS2015時搞砸了一些東西。所以我創建了標準的KMDF驅動程序項目,爲您提供了一個很好的框架。我在新項目中打開了靜態分析並像以前一樣定義了_PREFAST_,它也給我提供了相同的鏈接錯誤。

+0

這可能是因爲您正在獲取鎖而不在該函數中釋放它。你是否嘗試過在同一個函數中獲取和釋放,看看它是否能解決問題? – Serdalis

+0

@Serdalis如果我在同一個函數中獲取/釋放Wdf函數的鎖定,我相信prefast就可以。在助手功能中獲取鎖正在導致問題。但我想抽象出緩衝區的鎖定概念。我希望緩衝區的用戶能夠鎖定緩衝區,檢查其大小,添加一些數據,然後解鎖緩衝區。我不希望緩衝區的用戶知道鎖的工作方式。 –

+0

您的註釋適用於ppbBuf。你應該將它們應用於鎖定的元素。 –

回答

4

你正走在這條好路上。 事實上,你可以告訴PREfast的,你的功能鎖定或解鎖對象感謝SAL註釋: Annotating Locking Behavior

你還需要的PREfast講述的IRQL變化: IRQL annotations for drivers

下面是一個使用示例代碼根據你的代碼的註釋SAL,他們可能是從舊WDK7不同:

_IRQL_raises_(DISPATCH_LEVEL) 
_Acquires_lock_(ppbBuff->slLock) 
_Requires_lock_not_held_(ppbBuff->slLock) 
VOID PLxBufferLock(_In_ _IRQL_saves_ PPORT_BUFFER ppbBuff){ 
     WdfSpinLockAcquire(ppbBuff->slLock);  
} 

_Releases_lock_(ppbBuff->slLock) 
_Requires_lock_held_(ppbBuff->slLock) 
VOID PLxBufferUnlock(_In_ _IRQL_restores_ PPORT_BUFFER ppbBuff){ 
    WdfSpinLockRelease(ppbBuff->slLock); 
} 

備註:您應該使用註釋上ppbBuff->slLock變量,而不是其所有者。

UPDATE:看完上面的文件我有更新使用註釋後,_IRQL_saves_/_IRQL_restores_必須而不是在函數的函數參數一起使用。您可能還需要使用_IRQL_raises_。我編輯了上面的代碼示例。您也可以刪除_PREFAST_定義以避免鏈接問題。 _PREFAST_由編譯器在開始分析時定義。

更新2:而不是使用上_In_參數_IRQL_saves_/_IRQL_restores註解,你也可以使用_IRQL_saves_global_(kind, param)/_IRQL_restores_global_(kind, param)註釋的功能。這是一個更新的代碼示例:

_IRQL_raises_(DISPATCH_LEVEL) 
_Acquires_lock_(ppbBuff->slLock) 
_Requires_lock_not_held_(ppbBuff->slLock) 
_IRQL_saves_global_(SpinLock, ppbBuff) 
VOID PLxBufferLock(_In_ PPORT_BUFFER ppbBuff){ 
     WdfSpinLockAcquire(ppbBuff->slLock);  
} 

_Releases_lock_(ppbBuff->slLock) 
_Requires_lock_held_(ppbBuff->slLock) 
_IRQL_restores_global_(SpinLock, ppbBuff) 
VOID PLxBufferUnlock(_In_ PPORT_BUFFER ppbBuff){ 
    WdfSpinLockRelease(ppbBuff->slLock); 
} 
+0

感謝您的信息,我試過了,它似乎工作,但它導致我一個不同的問題。我用更多的信息編輯了這個問題。 –