共用方式為


使用__sdv_save_request和__sdv_retrieve_request處理延遲程序調用

延遲過程調用 (DPC) 對靜態驅動程式驗證器 (SDV) 提出挑戰,因為很難追蹤架構要求物件。 其中一個困難在於請求必須從全域指標中提取,通常會取自佇列的上下文或工作項目。 為了克服這個困難,靜態驅動程序驗證器提供兩個函式: __sdv_save_request__sdv_retrieve_request。 這些功能會將延遲的要求對應到 SDV 可以追蹤的要求。

__sdv_save_request__sdv_retrieve_request函式具有下列語法:

__sdv_save_request( request ) 
__sdv_retrieve_request( request ) 

其中 請求 可以是任何框架請求物件的句柄。

這些函式僅供靜態分析工具使用。 編譯程式會忽略函式。

下列程式代碼範例示範如何使用 __sdv_save_request 和 __sdv_retrieve_request 函式來引導 SDV,讓 SDV 可以對應延遲的要求。 SDV 可以使用此對應來驗證 DeferredRequestCompleted 規則。 DeferredRequestCompleted 規則要求 __sdv_save_request 和 __sdv_retrieve_request 出現在您的程序代碼中。 有兩個驅動程式屬性規則 (AliasWithinDispatchAliasWithinTimerDpc) 會尋找 __sdv_save_request 和 __sdv_retrieve_request 函式的存在。

在下列程式代碼範例中, EchoEvtIoRead 函式是 EvtIoRead 事件回呼函式,可將句柄儲存至佇列內容區域中的架構要求物件。 EchoEvtTimerFunc 函式是擷取它的 EvtTimerFunc 事件回呼函式。

VOID
EchoEvtIoRead(
 )in WDFQUEUE   Queue,
 __in WDFREQUEST Request,
 __in size_t      Length
    )
{
/* ..................... */
    // Mark the request as cancelable
    WdfRequestMarkCancelable(Request, EchoEvtRequestCancel);
 
 
    // Defer the completion to another thread from the timer DPC and save the handle to the framework request object by using the __sdv_save_request function. 
    queueContext->CurrentRequest = Request;    
 __sdv_save_request(Request);

    queueContext->CurrentStatus  = Status;

    return;
}

下列程式碼示例顯示了 __sdv_retrieve_request 函式對現有請求進行映射,以便 SDV 能追蹤其完成情況。

VOID
EchoEvtTimerFunc(
    IN WDFTIMER     Timer
    )
{...................................................
    queue = WdfTimerGetParentObject(Timer);
    queueContext = QueueGetContext(queue);

    //
    // The DPC is automatically synchronized to the queue lock,
    // so this prevents race conditions from occurring without explicit driver-managed locking. The __sdv_retrieve_request function is used so that SDV can restore the deferred request in the timer DPC. Because we know that this deferred request is valid (because it has been previously saved), the __analysis_assume function is used to suppress false defects that might otherwise result in this code path.

    //
 __sdv_retrieve_request(queueContext->CurrentRequest);
    Request = queueContext->CurrentRequest;
 __analysis_assume(Request != NULL);
    if( Request != NULL ) {

        //
        // Try to remove cancel status from the request.
        //
        // The request is not completed if it is already canceled
        // because the EchoEvtIoCancel function has run, or is about to run,
        // and we are racing with it. 

        Status = WdfRequestUnmarkCancelable(Request);
// Because we know that the request is not NULL in this code path and that the request is no longer marked cancelable, we can use the __analysis_assume function to suppress the reporting of a false defect. 

 __analysis_assume(Status != STATUS_CANCELLED);
        if( Status != STATUS_CANCELLED ) {

            queueContext->CurrentRequest = NULL;
            Status = queueContext->CurrentStatus;

            KdPrint(("CustomTimerDPC Completing request 0x%p, Status 0x%x \n", Request,Status));

            WdfRequestComplete(Request, Status);
        }
        else {
            KdPrint(("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not completing\n",
                                Request));
        }
    }

    return;
}