2016-05-17 144 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

感谢您的信息,我试过了,它似乎工作,但它导致我一个不同的问题。我用更多的信息编辑了这个问题。 –