6

Windows 7 32 ビット用のデバイス ドライバーを作成しています。WDK バージョン 7600.16385.1 を使用しています。これまでのところ順調に進んでいますが、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;

上記のバッファーをロックおよびロック解除できる2つの関数があります。

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 がどのように定義されているかを調べました。

__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 のリークに関する 2 つの警告から、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.

私はバッファを使用しており、どこにもバグチェックを行っていないため、正しくロックしていると思います。この場合、断食をなだめる方法を知っている人はいますか? ありがとう!

編集:

ロック機能を使用する例を次に示します。

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_ を追加しました。今はリンクエラーがたくさん出ますが、プリファストエラーはもうありません!

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_ を定義しましたが、同じリンク エラーが発生します。

4

1 に答える 1