So finden Sie Zeigermissbrauch in C.
Von Arthur Hicken
7. Juni 2012
3 min lesen
Zeiger sind sowohl die Stärke als auch die Achillesferse der Programmierung in C und C ++. Mit Zeigern können Sie zwar sehr kreativ und flexibel bei der Lösung eines bestimmten Problems vorgehen, es ist jedoch sehr einfach, Fehler unabsichtlich in Ihren Code einzufügen. Probleme mit Zeigern gehören zu den schwierigsten, auf die C-Programmierer stoßen. Vor einer Generation waren Brute-Force-Techniken wie das Einfügen von Druckanweisungen in den Code oft die beste Strategie, um diese Probleme zu finden.
Heute mögen Tools zur Erkennung von Speicherfehlern ++ versichern Zeigerprobleme können automatisch erkannt werden, wenn der Code erkannt wird, was viel Zeit und Kopfschmerzen spart. Insure ++ findet Probleme in den folgenden Kategorien:
- Operationen mit NULL-Zeigern. Operationen mit nicht initialisierten Zeigern.
- Operationen an Zeigern, die nicht auf gültige Daten verweisen.
- Operationen, die versuchen, Zeiger zu vergleichen oder auf andere Weise in Beziehung zu setzen, die nicht auf dasselbe Datenobjekt zeigen.
- Funktionsaufrufe über Funktionszeiger, die nicht auf Funktionen verweisen.
- Viele andere Ursachen für mögliches undefiniertes oder implementierungsdefiniertes Verhalten.
Insure ++ verwendet einen hochmodernen Code-Parser zusammen mit Hunderten von Heuristiken, um den Anwendungscode zu analysieren und dabei mehrere mögliche statische Verstöße zu melden. Während der Analyse des Codes wird eine neue Quellcodedatei geschrieben, wobei geeignete Instrumente in „Problemstellen“ eingefügt werden (z. B. Zeiger-Dereferenzierung, Scope-Exit usw.). Die resultierende Quelldatei wird automatisch kompiliert und alle resultierenden Objektcodedateien werden verknüpft in ein neues ausführbares Programm.
Beispiel
Unten finden Sie den Code für ein Programm "Hallo Welt", das die dynamische Speicherzuweisung verwendet:
/ * * Datei: hello.c * / #include #einschließen int main (int argc, char * argv []) {char * string, * string_so_far; int i, Länge; Länge = 0; für (i = 0; i
Die Grundidee dieses Programms ist, dass wir die aktuelle Zeichenfolgengröße in der variablen Länge verfolgen. Während jedes neue Argument verarbeitet wird, fügen wir seine Länge zur Längenvariablen hinzu und weisen einen Speicherblock der neuen Größe zu. Beachten Sie, dass der Code bei der Berechnung der Zeichenfolgenlänge (Zeile 14) und des Leerzeichens zwischen den Zeichenfolgen sorgfältig das letzte NULL-Zeichen enthält. Beides sind leicht zu machende Fehler. Es ist eine interessante Übung, um zu sehen, wie schnell Sie einen solchen Fehler mit einem Tool zur Erkennung von Speicherfehlern wie finden können Parasoft Insure ++.
Der Code kopiert das Argument entweder in den Puffer oder hängt es an, je nachdem, ob dies der erste Durchgang um die Schleife ist oder nicht. Schließlich zeigt der Zeiger string_so_far auf die neue längere Zeichenfolge.
Wenn Sie dieses Programm unter Insure ++ kompilieren und ausführen, werden "nicht initialisierte Zeiger" -Fehler angezeigt, die für den Code "strcpy (string, string_so_far)" gemeldet wurden. Dies liegt daran, dass die Variable string_so_far vor dem ersten Durchlaufen der Argumentschleife auf nichts gesetzt wurde. In einem kleinen Codebeispiel wie diesem ist ein solches Problem offensichtlich, aber selbst wenn der Fehler in einem Haufen von Hunderttausenden von Codezeilen vergraben ist und viel subtiler als der obige Fehler ist, wird Insure ++ ihn jedes Mal finden.
++ Berichte versichern
Insure ++ meldet alle gefundenen Probleme. Insure ++ - Berichte enthalten detaillierte Informationen, einschließlich: über die Art des Fehlers, die Quelldatei und die Zeilennummer, den tatsächlichen Inhalt der Quellcodezeile, den Ausdruck, der das Problem verursacht hat, einschließlich Berichte, einschließlich:
- Die Art des Fehlers (z. B. EXPR_UNRELATED_PTRCMP)
- Die Quelldatei und die Zeilennummer (z. B. foo.cc:42)
- Der tatsächliche Inhalt der Quellcodezeile (z. B. "while (p <g) {")
- Der Ausdruck, der das Problem verursacht hat (z. B. "p <g")
- Informationen zu allen am Fehler beteiligten Zeigern und Speicherblöcken:
- Die Zeigerwerte
- Die Speicherblöcke zeigten auf (falls vorhanden) und einen beliebigen Versatz
- Die Blockzuordnungsinformationen:
- Stapelverfolgung bei dynamischer Zuordnung.
- Blockdeklarationsspeicherort (Quelldatei und Zeilennummer), falls auf dem Stapel oder global zugewiesen.
- Gegebenenfalls Stapelverfolgung der Freigabe des Blocks.
- Die Stapelverfolgung zeigt, wie das Programm zum Fehlerort gelangt ist.
Um Parasoft Insure ++ zu testen, besuchen Sie bitte https://www.parasoft.com/products/parasoft-insure/insure-request-a-demo/.
Photo Credit: okay