Verwenden der _analysis_assume-Funktion zum Unterdrücken falscher Fehler
Sie können static Driver Verifier (SDV) mit zusätzlichen Informationen zu Ihrem Treiberquellcode bereitstellen, damit Sie während der Überprüfung die Meldungen über falsche Fehler unterdrücken können. Die falschen Fehler treten auf, wenn SDV einen offensichtlichen Regelverstoß meldet, aber in einer Situation, in der der Fahrer richtig handelt.
Verwenden Sie die Funktion __analysis_assume , um SDV diese zusätzlichen Informationen bereitzustellen. Die Funktion weist die folgende Syntax auf:
__analysis_assume( expression )
Dabei kann ausdruck ein beliebiger Ausdruck sein, von dem angenommen wird, dass er zu true ausgewertet wird.
Wenn Sie diese Funktion verwenden, geht SDV davon aus, dass die durch den Ausdruck dargestellte Bedingung an dem Punkt true ist, an dem die __analysis_assume-Funktion angezeigt wird. Die funktion __analysis_assume wird nur von den statischen Analysetools verwendet. Die Funktion wird vom Compiler ignoriert.
Wenn Sie __analysis_assume verwenden, ist es von entscheidender Bedeutung, dass Sie sicher sind, dass Sie die Gültigkeit der Annahme, die Sie treffen, sicher sind. Wenn sich herausstellt, dass Ihre Annahme jetzt oder in Zukunft falsch ist, können Sie einen wahren Fehler unterdrücken. Es wird empfohlen, ihrem Code immer einen Kommentar hinzuzufügen, der erläutert, warum Sie die __analysis_assume-Funktion verwenden. Wenn Sie keinen Grund für die Annahme schreiben können, unterdrücken Sie den Fehler nicht.
Sie sollten die __analysis_assume-Funktion nach Bedarf hinzufügen, wenn Sie falsche Fehler finden, die Sie sicher unterdrücken können.
Beispiele
Im folgenden Codebeispiel meldet die KMDF-Regel RequestCompletedLocal einen Fehler. Dies ist ein falscher Fehler, da SDV die switch-Anweisung nicht richtig interpretieren kann und folglich nicht in den Branch eintritt, in dem die Anforderung abgeschlossen ist.
In dieser switch-Anweisung gibt es sechs mögliche Fälle. Der Treiber hat sechs IOCTL-Codes definiert, sodass der Fahrer auf jeden Fall eine der Verzweigungen übernimmt. Wenn einer der Branches verwendet wird, wird die Anforderung erfolgreich abgeschlossen.
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;
}
}
Um den falschen Fehler sicher zu unterdrücken, verwenden Sie die funktion __analysis_assume , um anzugeben, dass ioControlCode garantiert eine der vom Treiber definierten IOCTLs ist.
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;
}
}
Ein weiteres Beispiel für die Verwendung von __analysis_assume finden Sie im Beispielcode, der unter Verwenden von __sdv_save_request und __sdv_retrieve_request für verzögerte Prozeduraufrufe verwendet wird. Das Beispiel zeigt, wie sie __sdv_save_request und __sdv_retrieve_request für DPCs (Arbeitselemente, Timer usw.) verwenden. Die funktion __analysis_assume wird verwendet, um falsche Fehler zu unterdrücken, die andernfalls auftreten könnten.