Indiana University Indiana University Indiana University

Auf dieser Seite:

  • Übersicht
  • Beispiele für häufige Segmentierungsfehler
  • Array-Referenzen außerhalb der Grenzen finden
  • Shell-Grenzwerte überprüfen
  • Verwenden Sie Debugger, um segmentierungsfehler

Übersicht

Ein Segmentierungsfehler (auch bekannt als Segfault) ist eine häufige Bedingung, die zum Absturz von Programmen führt. Sie werden oft mit einer Datei namens core . Segfaults werden durch ein Programm verursacht, das versucht, einen ungültigen Speicherort zu lesen oder zu schreiben.

Der Programmspeicher ist in verschiedene Segmente unterteilt: ein Textsegment für Programmanweisungen, ein Datensegment für Variablen und Arrays, die zur Kompilierungszeit definiert wurden, ein Stapelsegment für temporäre (oder automatische) Variablen, die in Unterprogrammen und Funktionen definiert sind, und ein Heapsegment für Variablen, die während der Laufzeit von Funktionen zugewiesen wurden, z. B. malloc (in C) und allocate (in Fortran). Weitere Informationen finden Sie unter Über Programmsegmente.

Ein Segfault tritt auf, wenn ein Verweis auf eine Variable außerhalb des Segments liegt, in dem sich diese Variable befindet, oder wenn versucht wird, an eine Position zu schreiben, die sich in einem schreibgeschützten Segment befindet. In der Praxis sind Segfaults fast immer darauf zurückzuführen, dass versucht wird, ein nicht vorhandenes Array-Element zu lesen oder zu schreiben, einen Zeiger vor der Verwendung nicht richtig zu definieren oder (in C-Programmen) versehentlich den Wert einer Variablen als Adresse zu verwenden (siehe das Beispiel scanf unten).

Beispiele für häufige Segfaults

  • Wenn Sie beispielsweise memset() wie unten gezeigt aufrufen, würde ein Programm zu einem Segfault führen:
    memset((char *)0x0, 1, 100);
  • Die folgenden drei Fälle veranschaulichen die häufigsten Arten von Array-bezogenen Segfaults:

    Fall A

    /* "Array out of bounds" error valid indices for array foo are 0, 1, ... 999 */ int foo; for (int i = 0; i <= 1000 ; i++) foo = i;

    Fall B

    /* Illegal memory access if value of n is not in the range 0, 1, ... 999 */ int n; int foo; for (int i = 0; i < n ; i++) foo = i;

    Fall C

    /* Illegal memory access because no memory is allocated for foo2 */ float *foo, *foo2; foo = (float*)malloc(1000); foo2 = 1.0;

    • Im Fall A array foo ist definiert für index = 0,1, 2, ... 999. In der letzten Iteration der Schleife for versucht das Programm jedoch auf foo zuzugreifen. Dies führt zu einem Segfault, wenn dieser Speicherort außerhalb des Speichersegments liegt, in dem sich foo befindet. Auch wenn es keinen Segfault verursacht, ist es immer noch ein Fehler.
    • In Fall B könnte integer n ein beliebiger Zufallswert sein. Wie in Fall A kann es zu einem Segfault kommen, wenn es nicht im Bereich 0, 1, ... 999 liegt. Ob es das tut oder nicht, es ist sicherlich ein Fehler.
    • In Fall C wurde die Speicherzuweisung für die Variable foo2 übersehen, sodass foo2 auf einen zufälligen Speicherort zeigt. Der Zugriff auf foo2 führt wahrscheinlich zu einem Segfault.
  • Ein weiterer häufiger Programmierfehler, der zu Segfaults führt, ist ein Versehen bei der Verwendung von Zeigern. Zum Beispiel erwartet die C-Funktion scanf() die Adresse einer Variablen als zweiten Parameter; Daher führt Folgendes wahrscheinlich dazu, dass das Programm mit einem segfault abstürzt:
    int foo = 0; scanf("%d", foo); /* Note missing & sign ; correct usage would have been &foo */

    Die Variable foo könnte am Speicherort definiert sein 1000, aber der obige Funktionsaufruf würde versuchen, ganzzahlige Daten in den Speicherort zu lesen 0 gemäß der Definition von foo.

  • Ein Segfault tritt auf, wenn ein Programm versucht, an einem Speicherort in einer Weise zu arbeiten, die nicht zulässig ist (z. B. würde der Versuch, einen schreibgeschützten Speicherort zu schreiben, zu einem Segfault führen).
  • Segfaults können auch auftreten, wenn Ihr Programm keinen Stapelplatz mehr hat. Dies ist möglicherweise kein Fehler in Ihrem Programm, sondern darauf zurückzuführen, dass Ihre Shell die Stapelgrößenbeschränkung zu klein eingestellt hat.

Array-Referenzen außerhalb der Grenzen finden

Die meisten Fortran-Compiler haben eine Option, die Code einfügt, um die Grenzen aller Array-Referenzen während der Laufzeit zu überprüfen. Wenn ein Zugriff außerhalb des für ein Array definierten Indexbereichs liegt, wird das Programm angehalten und Ihnen mitgeteilt, wo dies geschieht. Für die meisten Fortran-Compiler lautet die Option -C oder -check gefolgt von einem Schlüsselwort. Im Benutzerhandbuch Ihres Compilers finden Sie die genaue Option. Verwenden Sie die Begrenzungsprüfung nur beim Debuggen, da dies Ihr Programm verlangsamt. Einige C-Compiler haben auch eine Option zur Überprüfung von Grenzen.

Shell-Limits prüfen

Wie im letzten Beispiel oben erwähnt, sind einige Segfault-Probleme nicht auf Fehler in Ihrem Programm zurückzuführen, sondern werden stattdessen durch zu niedrige Systemspeicherlimits verursacht. Normalerweise ist es die Begrenzung der Stapelgröße, die diese Art von Problem verursacht. Verwenden Sie zum Überprüfen der Speicherbeschränkungen den Befehl ulimit in bash oder ksh oder den Befehl limit in csh odertcsh. Versuchen Sie, die Stacksize höher einzustellen, und führen Sie Ihr Programm erneut aus, um festzustellen, ob der Segfault verschwindet.

Verwenden Sie Debugger, um Segfaults zu diagnostizieren

Wenn Sie das Problem auf andere Weise nicht finden können, können Sie einen Debugger ausprobieren. Zum Beispiel könnten Sie Gnus bekannten Debugger GDB verwenden, um den Backtrace einer core -Datei anzuzeigen, die von Ihrem Programm gespeichert wurde; Wenn Programme einen Segfault ausführen, geben sie normalerweise den Inhalt (ihres Abschnitts des) Speichers zum Zeitpunkt des Absturzes in eine core -Datei aus. Starten Sie Ihren Debugger mit dem Befehl gdb core und verwenden Sie dann den Befehl backtrace, um zu sehen, wo sich das Programm beim Absturz befand. Mit diesem einfachen Trick können Sie sich auf diesen Teil des Codes konzentrieren.

Wenn die Verwendung von backtrace in der coreg-Datei das Problem nicht findet, müssen Sie das Programm möglicherweise unter Debugger-Kontrolle ausführen und dann jeweils eine Funktion oder eine Quellcodezeile durch den Code gehen. Dazu müssen Sie Ihren Code ohne Optimierung und mit dem Flag -g kompilieren, damit Informationen zu Quellcodezeilen in die ausführbare Datei eingebettet werden. Weitere Informationen finden Sie unter Schritt-für-Schritt-Beispiel für die Verwendung von GDB in Emacs zum Debuggen eines C- oder C ++ – Programms.

Zugehörige Dokumente

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.