Statische Analyse und Laufzeitfehlererkennung auf 64-Bit-Plattformen
Von Parasoft
14. Oktober 2010
3 min lesen
In meinem Frühere BeiträgeIch habe eine vierstufige Strategie zur Vorbereitung der Anwendung für den 64-Bit-Portierungsprozess behandelt:
- Wenden Sie Mutationstests an, um eine Laufzeitfehlererkennung durchzuführen
- Verwenden Sie die statische Codeanalyse, um fehleranfälligen und nicht portierbaren Code zu identifizieren
- Wiederholen Sie die Laufzeitfehlererkennung
- Unit-Tests durchführen (optional)
Zum Abschluss dieses Themas möchte ich eine Strategie zur Identifizierung von Fehlern auf dem 64-Bit-Prozessor vorstellen:
- Kompilieren Sie den Code auf dem 64-Bit-Prozessor neu
- Wiederholen statischer Analysecode Inspektion
- Verknüpfen und bauen
- Starten Sie die Anwendung
- Wiederholen Sie die Laufzeitfehlererkennung
Schritt 1: Kompilieren Sie den Code auf dem 64-Bit-Prozessor neu
Kompilieren Sie Ihre Anwendung auf dem 64-Bit-Prozessor neu. Wenn Sie Probleme beim Kompilieren haben, arbeiten Sie alle Macken im Zusammenhang mit Compiler-Variationen aus. Möglicherweise möchten Sie auch statische Codeanalyseregeln erstellen, die den mit diesen Macken verknüpften Code automatisch identifizieren, sodass Sie verhindern können, dass diese Kompilierungsprobleme in Zukunft auftreten.
Einige zu berücksichtigende Regeln weisen auf schwer zu portierende (auf 64 Bit) und fehleranfälligen Code hin. Betrachten Sie beispielsweise die folgenden Beispiele (weitere Details finden Sie hier Post):
Regeln, die fehleranfälligen Code verfügbar machen
- Geben Sie niemals einen Verweis auf ein lokales Objekt oder einen dereferenzierten Zeiger zurück, der durch "new" innerhalb der Funktion initialisiert wurde.
- Konvertieren Sie niemals eine Konstante in eine Nicht-Konstante. Dies kann die Datenintegrität untergraben, indem sich Werte ändern, die als konstant angenommen werden.
- Wenn eine Klasse virtuelle Funktionen hat, muss sie einen virtuellen Destruktor haben. Dieser Standard verhindert Speicherlecks in abgeleiteten Klassen.
- Öffentliche Mitgliedsfunktionen geben const-Handles an Mitgliedsdaten zurück.
- Wenn Sie Mitgliedsdaten nicht konstante Handles bereitstellen, untergraben Sie die Kapselung, indem Sie Anrufern erlauben, Mitgliedsdaten außerhalb der Mitgliedsfunktionen zu ändern.
- Ein Zeiger auf eine Klasse darf nicht in einen Zeiger einer zweiten Klasse konvertiert werden, es sei denn, er erbt von der zweiten. Dieses "ungültige" Downcasting kann zu Platzhaltern, Datenbeschädigungsproblemen und anderen Fehlern führen.
- Greifen Sie nicht direkt von einem Konstruktor auf globale Daten zu.
Ein benutzerdefinierter Regelsatz kann erstellt werden, indem die kritischen Regeln ausgewählt werden, die nur für diese bestimmte Aufgabe benötigt werden. Weitere Regeln können später nach Bedarf hinzugefügt werden.
Regeln, die schwer zu portierenden Code verfügbar machen
Nachdem Sie diesen fehleranfälligen Code gefunden und repariert haben, suchen Sie nach Code, der auf Ihrer aktuellen Plattform / Architektur einwandfrei funktioniert, aber möglicherweise nicht gut portiert werden kann. Einige Regeln, die für die meisten 64-Bit-Portierungsprojekte gelten, umfassen:
- Verwenden Sie gegebenenfalls Standardtypen.
- Überprüfen Sie alle vorhandenen Verwendungen langer Datentypen im Quellcode.
- Untersuchen Sie alle Fälle der Verengung der Zuordnung. Vermeiden Sie solche Zuweisungen, da die Zuweisung eines langen Werts zu einem int zum Abschneiden des 64-Bit-Werts führt.
- Finden Sie verengte Abgüsse. Verwenden Sie schmalere Umwandlungen für Ausdrücke, nicht für Operanden.
- Finde Casts von long * bis int *. In einer 32-Bit-Umgebung wurden diese möglicherweise synonym verwendet. Untersuchen Sie alle Instanzen inkompatibler Zeigerzuweisungen.
- Finde Casts von int * bis long *. In einer 32-Bit-Umgebung wurden diese möglicherweise synonym verwendet. Untersuchen Sie alle Instanzen inkompatibler Zeigerzuweisungen.
- Suchen Sie lange Werte, die mit int-Literalen initialisiert werden. Vermeiden Sie solche Initialisierungen, da Integralkonstanten möglicherweise als 32-Bit-Typen dargestellt werden, selbst wenn sie in Ausdrücken mit 64-Bit-Typen verwendet werden.
- Suchen Sie int-Literale in binären Operationen, für die das Ergebnis einem langen Wert zugewiesen ist. Eine 64-Bit-Multiplikation ist erwünscht, wenn das Ergebnis ein 64-Bit-Wert ist.
- Suchen Sie nach int-Konstanten, die in 64-Bit-Ausdrücken verwendet werden. Verwenden Sie 64-Bit-Werte in 64-Bit-Ausdrücken.
- Suchen Sie nach Verwendungen multiplikativer Ausdrücke, die in keinem der Operanden einen 64-Bit-Typ enthalten. Damit integrale Ausdrücke 64-Bit-Ergebnisse erzeugen, muss mindestens einer der Operanden einen 64-Bit-Datentyp mit oder ohne Vorzeichen haben.
- Verwenden Sie geeignete Suffixe für ganzzahlige und schwebende Literalkonstanten, wenn Ihr Compiler dies zulässt.
Schritt 2: Wiederholen Sie die Überprüfung des statischen Analysecodes
Nachdem Sie den Code neu kompiliert haben, führen Sie erneut eine statische Codeanalyse durch, um zu überprüfen, ob der neue Code allen entsprechenden Codierungsstandards entspricht. An diesem Punkt ist jede Änderung, die hätte vorgenommen werden sollen, aber nicht vorgenommen wurde, ein Fehler. Beheben Sie diese Fehler sofort! Sie möchten nicht nach diesen Fehlern suchen, während die Anwendung ausgeführt wird.
Schritt 3: Verknüpfen und erstellen
Verknüpfen Sie Ihre Anwendung und versuchen Sie, sie zu erstellen.
Schritt 4: Starten Sie die Anwendung
An diesem Punkt sollten Sie versuchen, Ihren Code auszuführen. Wenn Sie Probleme haben, Code auf dem 64-Bit-Prozessor auszuführen, verwenden Sie a Unit-Test-Framework den Code Funktion für Funktion ausführen; Auf diese Weise können Sie genau das spülen, was im Code nicht portierbar ist. Testen Sie die Funktion und beheben Sie das Problem. Setzen Sie diesen Vorgang fort, bis die gesamte Anwendung ausgeführt wird.
Schritt 5: Wiederholen Sie die Laufzeitfehlererkennung
Sobald die Anwendung ausgeführt wird, sollten Sie die Erkennung von Laufzeitfehlern wiederholen, da der Portierungsprozess wahrscheinlich einige neue Probleme verursacht, die vor dem Port nicht erkannt werden konnten (z. B. neue Speicherbeschädigungsprobleme oder anderes Verhalten). Wenn bei der Erkennung von Laufzeitfehlern Probleme auftreten, beheben Sie alle Fehler im Zusammenhang mit der Portierung.
***
Photo Credit: Jurvetson
Möchten Sie mehr erfahren? Schauen Sie sich unsere an Parasoft Insure ++Auf der Produktseite erfahren Sie, wie die Erkennung von Laufzeitfehlern Speicherbeschädigungen, Speicherlecks, Zugriff außerhalb der Array-Grenzen, ungültige Zeiger und andere Fehler aufdecken kann.