Mit der Version PVS-Studio 7.34 wurden eine Reihe neuer Diagnoseregeln in den Analysator eingeführt: Taint-Analyse für Java, Unity-spezifische Diagnoseregeln für C#, tiefer Einblick in OWASP und vieles mehr! In diesem Artikel werden sie alle behandelt.
In dieser Version konzentrierte sich das C-Team auf Diagnoseregeln für die allgemeine Analyse und die Unterstützung verschiedener Softwareentwicklungsstandards.
Aber behalten Sie Ihren Hut, das ist erst der Anfang! Das Team plant, noch mehr MISRA-Standarddiagnoseregeln abzudecken, also bleiben Sie dran für weitere Neuigkeiten :)
Und zunächst gehen wir die Hauptregeln in der Version 7.34 durch.
Diese Diagnoseregel dient zur Erkennung von Ausnahmen, die ohne erklärende Meldungen erstellt wurden.
Das Fehlen einer Meldung kann den Prozess der Fehlererkennung und -behebung sowie die allgemeine Lesbarkeit des Codes beeinträchtigen.
Hier ist ein Beispiel für Code, der den PVS-Studio-Analysator veranlasst, eine Warnung zu generieren:
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
Wenn ein Fehler auftritt, löst die SomeCheck-Funktion eine Ausnahme mit einer leeren Nachricht aus, die in der Foo-Funktion behandelt wird. Während der Verarbeitung wird erwartet, dass std::cerr Informationen über den Grund für die Ausnahme enthält, dies ist jedoch nicht der Fall.
Durch das Schreiben von Code auf diese Weise sendet ein Entwickler Wünsche für „viel Spaß beim Debuggen“ an seine Kollegen. Dies erschwert das Verständnis, was genau den Fehler verursacht hat.
Die Regel funktioniert für eine Standardausnahme. Sie können den benutzerdefinierten Anmerkungsmechanismus verwenden, um Warnungen für benutzerdefinierte Ausnahmen auszugeben.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Diese Diagnoseregel gilt nur für die C-Sprache.
Es zielt darauf ab, Fälle von Funktionstypdefinitionen zu erkennen, die const- oder volatile-Qualifizierer verwenden.
Gemäß dem C23-Standard (10. Punkt von Absatz 6.7.4.1) führt die Verwendung dieser Typen zu undefiniertem Verhalten.
Ein Beispiel für Code, der den PVS-Studio-Analysator veranlasst, eine Warnung zu generieren:
typedef int fun_t(void); typedef const fun_t const_qual_fun_t; // <= typedef const fun_t * ptr_to_const_qual_fun_t; // <= void foo() { const fun_t c_fun_t; // <= const fun_t * ptr_c_fun_t; // <= }
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Eine weitere Diagnoseregel für die C-Sprache, die beim Refactoring und Debuggen hilfreich sein kann.
Diese Regel ermöglicht es dem Analysator, implizite Umwandlungen von Ganzzahltypen in Aufzählungstypen zu erkennen.
Ein Codebeispiel mit der PVS-Studio-Warnung:
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
Dieser Code verwendet den bedingten Operator (?:), um zwischen zwei ganzzahligen Variablen posOne und posTwo zu wählen, was zu einer impliziten Umwandlung führt.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Hier ist eine neue Diagnoseregel, die sich auf Sicherheit konzentriert und an den SAST-Prinzipien ausgerichtet ist.
Diese Regel wurde gemäß dem OWASP-Sicherheitsüberprüfungsstandard entwickelt.
Es zielt darauf ab, Aufrufe veralteter kryptografischer Funktionen zu erkennen. Ihre Verwendung kann zu kritischen Software-Sicherheitsproblemen führen.
Ein Codebeispiel mit der PVS-Studio-Warnung:
typedef int fun_t(void); typedef const fun_t const_qual_fun_t; // <= typedef const fun_t * ptr_to_const_qual_fun_t; // <= void foo() { const fun_t c_fun_t; // <= const fun_t * ptr_c_fun_t; // <= }
Laut Microsoft-Dokumentation sind die Funktionen CryptoImportKey und CryptoDestroyKey veraltet. Diese sollten durch sichere Gegenstücke von Cryptography Next Generation (BCryptoImportKey und BCryptoDestroyKey) ersetzt werden.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Aber das ist nur zum Aufwärmen! Das C- und C-Team plant, noch mehr Diagnoseregeln für verschiedene Softwareentwicklungsstandards abzudecken. Besonderes Augenmerk wird auf den MISRA-Standard gelegt. Also, warte auf die Neuigkeiten :)
In der neuen Version von PVS-Studio 7.34 konzentrierte sich das C#-Team auf die Erstellung Unity-spezifischer Diagnoseregeln, vergaß aber auch die allgemeinen Analyseregeln nicht.
Beginnen wir mit Letzterem.
Diese neue Diagnoseregel zielt darauf ab, eine fehlerhafte Verwendung des Nicht-A- oder B-Musters zu erkennen. Das Problem rührt von der Verwirrung der Entwickler über die Operationspriorität her.
Ein Codebeispiel mit der PVS-Studio-Warnung:
Orientation GetOrientation (bool b) { int posOne = 1; int posTwo = 2; return b ? posOne : posTwo; // V2022 }
Zu Beginn der Methode wird der Eingabeparameterschlüssel auf eine leere Zeichenfolge oder Null überprüft.
Aber es liegt ein Fehler in der Logik des bedingten Ausdrucks vor. Die Priorität des Nicht-Operators ist höher als die des Oder-Operators. Daher gilt die Negation nicht für die rechte Seite des Ausdrucks. Auch wenn der Schlüssel auf null gesetzt ist, ist die Bedingung wahr.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Dies ist die erste Diagnoseregel in einer neuen Reihe von Unity-spezifischen Regeln.
Es zielt darauf ab, die Verwendung von UnityEngine.Object (oder anderen davon geerbten Objekten) zusammen mit System.WeakReference zu erkennen.
Aufgrund der impliziten Nutzung der Instanz durch die Engine selbst kann das Verhalten einer schwachen Referenz vom erwarteten abweichen.
Ein Codebeispiel mit der PVS-Studio-Warnung:
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
Im Beispiel sehen wir einen schwachen Verweis auf ein Objekt der GameObject-Klasse. Selbst wenn ein Autor keine starken Verweise auf dieses Objekt erstellt hat, kann der Garbage Collector es nicht bereinigen.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
In einer anderen Diagnoseregel für Unity sucht der Analysator mit dem Wait-Operator nach Orten mit mehreren Verwendungen desselben UnityEngine.Awaitable-Objekts.
Objekte werden zu Optimierungszwecken in einem Objektpool gespeichert.
Beim Wait-Call wird das Awaitable-Objekt an den Pool zurückgegeben. Wenn „await“ danach erneut auf dasselbe Objekt angewendet wird, erhalten wir eine Ausnahme. In manchen Fällen ist auch ein Deadlock möglich.
Ein Codebeispiel mit der PVS-Studio-Warnung:
typedef int fun_t(void); typedef const fun_t const_qual_fun_t; // <= typedef const fun_t * ptr_to_const_qual_fun_t; // <= void foo() { const fun_t c_fun_t; // <= const fun_t * ptr_c_fun_t; // <= }
In diesem Code erhalten wir eine Ausnahme oder einen Deadlock. Lassen Sie mich erklären, warum. Wir erhalten einen Wert mithilfe des Wait-Aufrufs von „awaitable“. Dann initialisieren wir die Ergebnisvariable mit diesem Wert. Der Deadlock tritt auf, da „await“ zuvor in einer bedingten Konstruktion auf „awaitable“ angewendet wurde.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Diese Diagnoseregel zielt darauf ab, Anomalien im Zusammenhang mit Aufrufen der Methoden Destroy oder DestroyImmediate der Klasse UnityEngine.Object zu erkennen.
Das Problem tritt in einer Situation auf, in der ein Argument vom Typ UnityEngine.Transform verwendet wird. Dies führt zu einem Fehler beim Methodenaufruf. Das Entfernen der Transform-Komponente aus einem Spielobjekt ist in Unity nicht zulässig.
Ein Codebeispiel mit der PVS-Studio-Warnung:
Orientation GetOrientation (bool b) { int posOne = 1; int posTwo = 2; return b ? posOne : posTwo; // V2022 }
Die Transformationseigenschaft der MonoBehaviour-Basisklasse gibt eine Instanz der Transform-Klasse zurück, die als Argument an die Destroy-Methode übergeben wird.
Beim Aufruf der Methode auf diese Weise gibt Unity eine Fehlermeldung aus, aber die Komponente selbst wird nicht zerstört.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Diese Diagnoseregel zielt auf einen anderen Fehlerbereich ab – Leistungsprobleme.
Wenn Sie daran interessiert sind, wie statische Analysen zur Optimierung von Unity-Projekten beitragen können, lade ich Sie ein, diesen Artikel zu lesen.
Der Zweck dieser Regel besteht darin, dem Analysator dabei zu helfen, die Erstellung von Unity-Objekten in einer häufig ausgeführten Methode zu erkennen.
Die regelmäßige Erstellung/Zerstörung von Spielobjekten belastet nicht nur die CPU, sondern führt auch zu einer erhöhten Häufigkeit von Garbage Collector-Aufrufen. Dies wirkt sich auf die Leistung aus.
Ein Codebeispiel mit der PVS-Studio-Warnung:
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
Hier in der Update-Methode wird ein Spielobjekt _instance erstellt und zerstört. Da Update jedes Mal ausgeführt wird, wenn die Frames aktualisiert werden, wird empfohlen, diese Vorgänge darin nach Möglichkeit zu vermeiden.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Weitere Unity-Diagnosen stehen übrigens noch bevor! Machen Sie sich bereit für gute Neuigkeiten von unserem Team :)
Wir können Ihnen nur von einer wichtigen Verbesserung im C#-Analysator erzählen – der Verfolgung von Änderungen des Methodenrückgabewerts zwischen Aufrufen. Was ändert sich? Lass es uns aufschlüsseln.
Sehen Sie sich dieses Beispiel an:
typedef int fun_t(void); typedef const fun_t const_qual_fun_t; // <= typedef const fun_t * ptr_to_const_qual_fun_t; // <= void foo() { const fun_t c_fun_t; // <= const fun_t * ptr_c_fun_t; // <= }
Die Methode „Example()“ prüft den Rückgabewert von Foo() auf Null. Die Foo()-Methode wird dann im Hauptteil der Bedingung erneut aufgerufen und ihr Rückgabewert wird dereferenziert.
Früher generierte der Analysator in diesem Fall eine Warnung, da er den Kontext eines Aufrufs nicht berücksichtigte und sich nur auf den Code seiner Deklaration konzentrierte. Der Analysator implizierte früher, dass null zurückgegeben werden könnte.
Jetzt versteht der Analysator, dass Foo() in beiden Fällen den gleichen Wert zurückgibt und es keine Warnung gibt.
Aber schauen wir uns ein Beispiel mit leicht geändertem Code an...
Orientation GetOrientation (bool b) { int posOne = 1; int posTwo = 2; return b ? posOne : posTwo; // V2022 }
Aus der Methodendeklaration Foo() können wir entnehmen, dass die Methode bei _condition == true nicht null zurückgibt.
Der Analysator sieht die Änderung des Felds _condition vor dem zweiten Aufruf und geht davon aus: Wenn sich das in Foo() verwendete Feld geändert hat, hat sich möglicherweise auch der Rückgabewert von Foo() geändert.
Daher bleiben Warnungen vor einer möglichen Dereferenzierung bestehen.
Der C#-Analysator unterstützt jetzt die Analyse von .NET 9-Projekten! Erfahren Sie hier mehr über diese und andere neue Funktionen in PVS-Studio 7.34.
Mit der Veröffentlichung von PVS-Studio 7.34 verfügt der Java-Analysator jetzt über einen Mechanismus zur Taint-Analyse!
Dieser Mechanismus wurde zur Grundlage für die erste Diagnoseregel – die Suche nach SQL-Injections. Zukünftige Updates des Java-Analysators werden sich auf SAST, die OWASP-Top-10-Liste der häufigsten potenziellen Schwachstellen, und andere Taint-bezogene Diagnoseregeln konzentrieren.
Beginnen wir jetzt mit einigen neuen allgemeinen Analyseregeln, denn auch diese lohnen sich.
Diese neue Diagnoseregel hebt Bereiche im Code hervor, in denen Werte von Postfix-Operationen nicht verwendet werden.
Das Problem besteht darin, dass entweder eine Operation überflüssig ist oder, was noch schlimmer ist, die Operationen durcheinander geraten sind und ein Entwickler das Präfix eins verwenden wollte.
Ein Codebeispiel mit der PVS-Studio-Warnung:
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
Der Operator hat keinen Einfluss auf den Wert, den die Methode „calcuteSomething“ zurückgibt.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Wie Sie dem Namen dieser Diagnoseregel entnehmen können, erkennt sie einen möglichen Überlauf.
Ein Codebeispiel mit der PVS-Studio-Warnung:
typedef int fun_t(void); typedef const fun_t const_qual_fun_t; // <= typedef const fun_t * ptr_to_const_qual_fun_t; // <= void foo() { const fun_t c_fun_t; // <= const fun_t * ptr_c_fun_t; // <= }
Einer Ganzzahlvariablen wurde ein Wert außerhalb des gültigen Bereichs zugewiesen, was zu einem Überlauf führt.
Variablen speichern offensichtlich andere Werte als die, die der Entwickler zuzuweisen versucht hat.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Diese Diagnose hilft bei der Identifizierung von Synchronisierungsproblemen.
Ein Codebeispiel mit der PVS-Studio-Warnung:
Orientation GetOrientation (bool b) { int posOne = 1; int posTwo = 2; return b ? posOne : posTwo; // V2022 }
Der Analysator erkennt die Methoden „wait“, „notify“ und „notifyAll“, da sie möglicherweise in einem nicht synchronisierten Kontext aufgerufen werden. Sie arbeiten mit dem Monitor des Objekts, über das die Synchronisierung erfolgt. Das heißt, ihr Aufruf ist nur im synchronisierten Kontext und nur für das Objekt korrekt, durch das die Synchronisierung erfolgt.
Wenn die Methoden „wait“, „notify“ oder „notifyAll“ in einem nicht synchronisierten Kontext oder für das falsche Objekt aufgerufen werden, erhalten wir die Ausnahme „IllegalMonitorStateException“.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Die erste Taint-bezogene Diagnoseregel des Java-Analyzers! Genauer gesagt kann der Analysator jetzt potenzielle SQL-Injections erkennen.
SQL-Injection ist eine Schwachstelle, die es einem Angreifer ermöglicht, seinen Code in eine SQL-Abfrage einzuschleusen. Wenn die Abfrage externe Daten verwendet, ohne diese korrekt zu validieren, riskiert man die Integrität und Vertraulichkeit der in einer Datenbank gespeicherten Informationen.
void SomeCheck(const char *val) { if (!val) throw std::runtime_error { "" }; .... } void Foo() { const char *val = ....; try { SomeCheck(val); // <= } catch(std::runtime_error &err) { std::cerr << err.what() << std::endl; } }
Falls sich herausstellt, dass der Benutzer böswillig ist und der Wert von param ungefähr der folgende ist: „111“ oder 1=1; Tabellenbenutzer löschen; auswählen „“, können Sie sich von der Benutzertabelle verabschieden. Daher ist es wichtig, die externen Daten zu überprüfen.
Weitere Einzelheiten zu dieser Diagnoseregel finden Sie in der Dokumentation.
Danke fürs Lesen!
Wenn Sie Anfragen zu Artikeln oder Fragen haben, zögern Sie nicht, diese über das Feedback-Formular zu senden. Zu guter Letzt würden wir gerne Ihre Meinung in den Kommentaren hören:)
Das obige ist der detaillierte Inhalt vonNeue Diagnoseregeln in PVS-Studio 4. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!