Static Driver Verifier – Allgemeines Tool und technische Einschränkungen
SDV weist die folgenden allgemeinen Einschränkungen auf:
SDV überprüft jeweils nur einen Treiber, und der Treiber muss einem der folgenden Treibermodelle folgen, um vollständig überprüft zu werden: WDM, KMDF, NDIS oder Storport. Weitere Informationen zu den unterstützten Treibern finden Sie unter Ermitteln, ob die statische Treiberüberprüfung Ihren Treiber oder Ihre Bibliothek unterstützt.
Treiber, die nicht in eine der oben genannten Kategorien fallen, werden in den Regeln, die überprüft werden können, stark eingeschränkt und sind bei der Analyse wahrscheinlicher, dass sie fehlschlagen.
Die Treiberprojektdatei und der Quellcode müssen sich auf dem lokalen Computer befinden. Sie können Treiber nicht remote überprüfen.
SDV wird mit dem Gebietsschema Englisch (USA) installiert. Daher verwenden gebietsschemaabhängige Elemente, z. B. die Zeichenfolgenformatierung, die englischen (USA) Varianten. Diese Einschränkung ist auch dann vorhanden, wenn SDV unter lokalisierten Versionen von Windows außer Englisch (USA) installiert wird.
Die SDV-Überprüfungs-Engine weist technische Einschränkungen auf, die verhindern, dass einige Treibercode richtig interpretiert werden. Insbesondere die Überprüfungs-Engine:
Erkennt nicht, dass 32-Bit-Ganzzahlen auf 32 Bits beschränkt sind. Daher werden keine Überlauf- oder Unterlauffehler erkannt.
Stellt sicher, dass Treiber, die ihre Einstiegspunkte mit dem statischen Schlüsselwort (keyword) deklarieren, ordnungsgemäß verarbeitet werden. Um jedoch sicherzustellen, dass statische Einstiegspunkte erkannt werden, erfordert SDV eine Änderung an den Sdv-map.h-Dateien für statische Funktionen: Wenn Sie z. B. einen statischen Einstiegspunkt deklarieren:
static DRIVER_UNLOAD Unload;
Sdv-map.h enthält nicht den üblichen Eintrag für fun_DriverUnload.
#define fun_DriverUnload Unload
Stattdessen sehen Sie, dass der Funktionsname mangled ist:
#define fun_DriverUnload sdv_static_function_Unload_1
Dies ist erforderlich, da mehrere Module möglicherweise über eine statische Funktion namens Unload verfügen. Der Name wird verwaltet, um potenzielle Konflikte zu vermeiden.
Treiberverteilungs- oder Treiberrückruffunktionen, die in einem Exporttreiber definiert sind, können nicht interpretiert werden, wenn der Exporttreiber über eine Moduldefinitionsdatei (DEF) verfügt, die die Treiberverteilungsfunktion ausblendet. Um dieses Problem zu vermeiden, fügen Sie die Treiberverteilungsfunktion zum Abschnitt EXPORTS der Moduldefinitionsdatei (.def) hinzu.
Der Rollentyp einer Funktion kann nicht erfolgreich erkannt werden, wenn die folgenden Verweise auf diese Funktion nicht in derselben Kompilierungseinheit enthalten sind.
- Deklaration der Funktion.
- Definition der Funktion.
- Zuweisung der Funktion zu einem Treibereinstiegspunkt oder einer Rückruffunktion.
Die Kompilierungseinheit wird hier als kleinster Satz von Quellcodedateien und anderen Quelldateien definiert, die in dieser Quellcodedatei enthalten sind.
Wenn ein Funktionsrollentyp von SDV nicht erkannt wird, überprüft SDV nicht die Ablaufverfolgungen, die von dieser Funktion stammen.
Beispiel: Ein Treiber definiert (oder implementiert) eine EvtDriverDeviceAdd-Funktion in der Datei mydriver.c. Diese Kompilierungseinheit (oder alle H-Dateien, die mydriver.c enthält) muss die Funktionsrollentypdeklaration für die EvtDriverDeviceAdd-Funktion enthalten.
Interpretiert keine strukturierte Ausnahmebehandlung. Für try/except-Anweisungen analysiert SDV den überwachten Abschnitt so, als ob keine Ausnahme ausgelöst wird. Analysiert nicht den Ausdruck oder den Ausnahmehandlercode.
// The try/except statement __try { // guarded section } __except ( expression ) { // exception handler }
Für try/finally-Anweisungen analysiert SDV den überwachten Abschnitt und dann den Beendigungshandler, als ob keine Ausnahme ausgelöst würde.
// The try/finally statement __try { // guarded section } __finally { // termination handler }
Sowohl für try/except - als auch für try/finally-Anweisungen ignoriert SDV die Leave-Anweisung .
Sowohl für try/except - als auch für try/finally-Anweisungen verhindert ein Sprung aus dem try-Block die Analyse der except - oder finally-Anweisungen . Informationen zum erneuten Schreiben, damit Sie eine leave-Anweisung verwenden können, finden Sie im Thema zur Compilerwarnung C6242.
Ignoriert die Zeigerarithmetik. Beispielsweise werden Situationen übersehen, in denen ein Zeiger erhöht oder verringert wird. Diese Einschränkung kann zu falsch negativen und falsch positiven Ergebnissen führen.
Ignoriert Unions. In den meisten Fällen wird eine Union als Struktur behandelt, und dies kann zu falsch positiven ergebnissen oder falsch negativen Ergebnissen führen.
Ignoriert Umwandlungsvorgänge, sodass sowohl Fehler, die durch Neucasting gelöst werden, als auch Fehler, die durch Umwandlung verursacht werden, fehlen. Die Engine geht beispielsweise davon aus, dass eine ganze Zahl, die als Zeichen neu umgewandelt wird, weiterhin den ganzzahligen Wert aufweist.
Initialisiert nur Arrays, die Funktionszeigerarrays sind. SDV gibt eine Warnung aus und komprimiert den Arrayinitialisierer auf die ersten 1000 Elemente. Bei anderen Arraytypen wird nur das erste Element initialisiert.
Konstruktoren von Objekten, die in Arrays initialisiert werden, werden nicht aufgerufen. Im folgenden Codeausschnitt wird x beispielsweise nicht auf 10 festgelegt, da SDV den Konstruktor nicht aufruft.
class A { public: A() { x = 10; } int x; }; void main() { A a[1]; }
SDV unterstützt die Verwendung von Konstruktoren zum Initialisieren von Arrays nicht. Im folgenden Codeausschnitt wird beispielsweise der Konstruktor für P in der funktion Standard nicht ordnungsgemäß aufgerufen und initialisiert das Element im Array p2 nicht:
class P { public: P() : x(0) {} int x; }; void main() { P* p1 = new P[1]; P p2[1] = {P()}; }
SDV ignoriert vorkompilierte Header. Treiber, die vorkompilierte Header ausschließlich zur Beschleunigung der Kompilierung verwenden, werden mit SDV langsamer kompiliert. Treiber, die vorkompilierte Header für eine erfolgreiche Kompilierung verwenden müssen, werden nicht mit SDV kompiliert.
Einige Arten impliziter Zuweisungen, die über Aufrufe von RtlZeroMemory oder NdisZeroMemory vorgenommen werden, können nicht abgeleitet werden. Die Engine führt eine Analyse nach besten Kräften durch, um den Arbeitsspeicher auf 0 (null) zu initialisieren, aber nur, wenn der Typ identifiziert werden kann. Daher kann Code, der von diesen Funktionen zum Initialisieren des Arbeitsspeichers abhängig ist, entlang einiger Codepfade zu falschen Fehlern führen.
Unterstützt kein Speichermodell, mit dem die manuelle Verteilung von E/A-Anforderungen an einen KMDF-Treiber nachverfolgt werden kann. Die Engine unterstützt nur Methoden, die auf dem Framework basieren, um die E/A-Anforderungen an den Treiber zu übermitteln (für sequenzielle oder parallele Verteilung).
Die Verwendung des Float-Datentyps für Vergleiche wird nicht unterstützt. Diese technische Einschränkung kann zu falsch negativen und falsch positiven Ergebnissen führen.
SDV unterstützt keine virtuelle Vererbung oder virtuelle Funktionen. SDV generiert keine Fehler, die einem Codepfad durch virtuelle Funktionen folgen, was zu verloren gegangenen echten Fehlern führen kann. Die virtuelle Vererbung wird wie eine reguläre Vererbung behandelt, was zu falschen Fehlern oder verloren gegangenen wahren Fehlern führen kann.