誤検知を抑制するための _analysis_assume 関数の使用
検証中に誤った欠陥のレポートを抑制できるように、ドライバーのソース コードに関する追加情報を静的ドライバー検証ツール (SDV) に提供できます。 誤った欠陥は、SDV が明らかな規則違反を報告するが、ドライバーが正しく動作している状況で発生します。
この追加情報を SDV に提供するには、__analysis_assume 関数を使用します。 関数のクエリは次の構文のとおりです:
__analysis_assume( expression )
ここで 、表現には、true と評価されると見なされる任意の式を指定できます。
この関数を使用すると、SDVは、__analysis_assume 関数が出現する時点で、表現によって表される条件が true であると見なします。 __analysis_assume関数は、静的分析ツールでのみ使用されます。 関数はコンパイラによって無視されます。
__analysis_assume を使用する場合は、想定の有効性を確認することが非常に重要です。 現在または将来、想定が誤りであることが判明した場合は、真の欠陥を抑制できる可能性があります。 __analysis_assume 関数を使用する理由を説明するコメントをコードに常に追加することをお勧めします。 想定の理由を記述できない場合は、欠陥を抑制しないでください。
安全に抑制できる誤った欠陥が見つかるたびに、必要に応じて __analysis_assume 関数を追加する必要があります。
例
次のコード例では、KMDF 規則 RequestCompletedLocal が欠陥を報告します。 SDV が switch ステートメントを正しく解釈できず、その結果、要求が完了したブランチに入らないため、これは誤った欠陥です。
この switch ステートメントでは、6 つのケースが考えられます。 ドライバーは 6 つの IOCTL コードを定義しているため、ドライバーは間違いなくいずれかの分岐を取得します。 いずれかのブランチが作成されると、要求は正常に完了します。
VOID
PortIOEvtIoDeviceControl(
__in WDFQUEUE Queue,
__in WDFREQUEST Request,
__in size_t OutputBufferLength,
__in size_t InputBufferLength,
__in ULONG IoControlCode
)
PDEVICE_CONTEXT devContext = NULL;
WDFDEVICE device;
PAGED_CODE();
device = WdfIoQueueGetDevice(Queue);
devContext = PortIOGetDeviceContext(device);
switch(IoControlCode)
case IOCTL_GPD_READ_PORT_UCHAR:
case IOCTL_GPD_READ_PORT_USHORT:
case IOCTL_GPD_READ_PORT_ULONG:
PortIOIoctlReadPort(devContext,
Request,
OutputBufferLength,
InputBufferLength,
IoControlCode);
break;
case IOCTL_GPD_WRITE_PORT_UCHAR:
case IOCTL_GPD_WRITE_PORT_USHORT:
case IOCTL_GPD_WRITE_PORT_ULONG:
PortIOIoctlWritePort(devContext,
Request,
OutputBufferLength,
InputBufferLength,
IoControlCode);
break;
}
}
誤った欠陥を安全に抑制するには、__analysis_assume関数を使用して、IoControlCode がドライバーが定義した IOCTL のいずれかであることが保証されることを指定します。
VOID
PortIOEvtIoDeviceControl(
__in WDFQUEUE Queue,
__in WDFREQUEST Request,
__in size_t OutputBufferLength,
__in size_t InputBufferLength,
__in ULONG IoControlCode
)
PDEVICE_CONTEXT devContext = NULL;
WDFDEVICE device;
PAGED_CODE();
device = WdfIoQueueGetDevice(Queue);
devContext = PortIOGetDeviceContext(device);
/* Use __analysis_assume to suppress a false defect for the SDV RequestCompletedLocal rule.
There are only 6 possible IOCTLs for IoControlCode; each case is covered in the switch statement.
*/
__analysis_assume( IoControlCode == IOCTL_GPD_READ_PORT_UCHAR || \
IoControlCode == IOCTL_GPD_READ_PORT_USHORT|| \
IoControlCode == IOCTL_GPD_READ_PORT_ULONG || \
IoControlCode == IOCTL_GPD_WRITE_PORT_UCHAR|| \
IoControlCode == IOCTL_GPD_WRITE_PORT_USHORT|| \
IoControlCode == IOCTL_GPD_WRITE_PORT_ULONG);
switch(IoControlCode)
case IOCTL_GPD_READ_PORT_UCHAR:
case IOCTL_GPD_READ_PORT_USHORT:
case IOCTL_GPD_READ_PORT_ULONG:
PortIOIoctlReadPort(devContext,
Request,
OutputBufferLength,
InputBufferLength,
IoControlCode);
break;
case IOCTL_GPD_WRITE_PORT_UCHAR:
case IOCTL_GPD_WRITE_PORT_USHORT:
case IOCTL_GPD_WRITE_PORT_ULONG:
PortIOIoctlWritePort(devContext,
Request,
OutputBufferLength,
InputBufferLength,
IoControlCode);
break;
}
}
__analysis_assumeを使用する方法の別の例については、「遅延プロシージャ呼び出しの__sdv_save_requestと__sdv_retrieve_requestの使用」で使用するコード例を参照してください。 この例では、DPC (作業項目、タイマーなど) に __sdv_save_request と __sdv_retrieve_request を使用する方法を示します。 __analysis_assume関数は、それ以外の場合に発生する可能性がある誤った欠陥を抑制するために使用されます。