c++ - segmentation - sigsegv




Was ist ein Segmentierungsfehler? (8)

Was ist ein Segmentierungsfehler? Ist es in C und C ++ anders? Wie hängen Segmentierungsfehler und freie Zeiger zusammen?


Die Wikipedia-Seite " Segmentation_fault " enthält eine sehr schöne Beschreibung, die nur auf die Ursachen und Gründe hinweist. Schaue im Wiki nach einer detaillierten Beschreibung.

Ein Segmentierungsfehler (oft als segfault abgekürzt) oder Zugriffsverletzung ist ein Fehler, der von Hardware mit Speicherschutz ausgelöst wird und ein Betriebssystem (OS) über eine Speicherzugriffsverletzung benachrichtigt.

Im Folgenden sind einige typische Ursachen für einen Segmentierungsfehler aufgeführt:

  • Dereferenzierung von NULL-Zeigern - dies ist speziell auf die Speicherverwaltungshardware zurückzuführen
  • Versuch, auf eine nicht vorhandene Speicheradresse zuzugreifen (außerhalb des Adressbereichs des Prozesses)
  • Versuch, auf Speicher zuzugreifen, für den das Programm keine Rechte hat (z. B. Kernel-Strukturen im Prozesskontext)
  • Versuch, schreibgeschützten Speicher zu schreiben (z. B. Code-Segment)

Diese wiederum werden häufig durch Programmierfehler verursacht, die zu einem ungültigen Speicherzugriff führen:

  • Dereferenzieren oder Zuweisung zu einem nicht initialisierten Zeiger (wilder Zeiger, der auf eine zufällige Speicheradresse zeigt)

  • Dereferenzieren oder Zuweisung zu einem freigelassenen Zeiger (Dangling-Zeiger, der auf Speicher zeigt, der freigegeben / freigegeben / gelöscht wurde)

  • Ein Pufferüberlauf.

  • Ein Stapelüberlauf.

  • Versuch, ein Programm auszuführen, das nicht korrekt kompiliert wird. (Einige Compiler geben trotz des Vorhandenseins von Kompilierungsfehlern eine ausführbare Datei aus.)


Ein Segmentierungsfehler oder eine Zugriffsverletzung tritt auf, wenn ein Programm versucht, auf einen Speicherbereich zuzugreifen, der nicht existiert, oder versucht, auf einen Speicherort zuzugreifen, der nicht erlaubt ist.

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

Hier ist [1000] nicht vorhanden, also tritt segfault auf.

Ursachen für Segmentierungsfehler:

it arise primarily due to errors in use of pointers for virtual memory addressing, particularly illegal access.

De-referencing NULL pointers – this is special-cased by memory management hardware.

Attempting to access a nonexistent memory address (outside process’s address space).

Attempting to access memory the program does not have rights to (such as kernel structures in process context).

Attempting to write read-only memory (such as code segment).

Es ist erwähnenswert, dass der Segmentierungsfehler nicht durch den direkten Zugriff auf einen anderen Prozessspeicher verursacht wird (dies höre ich manchmal), da dies einfach nicht möglich ist. Bei virtuellem Speicher hat jeder Prozess seinen eigenen virtuellen Adressraum und es gibt keine Möglichkeit, mit einem Zeiger auf einen anderen zuzugreifen. Ausgenommen davon können gemeinsam genutzte Bibliotheken sein, die dem gleichen physischen Adressraum (möglicherweise) unterschiedlichen virtuellen Adressen und Kernel-Speicher zugeordnet sind, der in jedem Prozess sogar auf die gleiche Weise abgebildet wird (um TLB-Flushing auf Syscall zu vermeiden, denke ich). Und Dinge wie shmat;) - das ist was ich als "indirekten" Zugang zähle. Man kann jedoch überprüfen, dass sie normalerweise weit vom Prozesscode entfernt sind, und wir können normalerweise auf sie zugreifen (deshalb sind sie dort, dennoch wird ein Segmentierungsfehler erzeugt, wenn man auf sie inkorrekt zugreift).

Dennoch kann ein Segmentierungsfehler auftreten, wenn auf unseren eigenen (Prozess-) Speicher in einer ungeeigneten Weise zugegriffen wird (beispielsweise indem versucht wird, in nicht beschreibbaren Raum zu schreiben). Der häufigste Grund dafür ist der Zugriff auf den Teil des virtuellen Adressraums, der überhaupt nicht dem physischen Adressraum zugeordnet ist.

Und all das in Bezug auf virtuelle Speichersysteme.


In einfachen Worten: Segmentierungsfehler ist das Betriebssystem, das ein Signal an das Programm sendet, das besagt, dass es einen unzulässigen Speicherzugriff erkannt hat und das Programm vorzeitig beendet, um zu verhindern, dass Speicher beschädigt wird.


Segmentierungsfehler sind eine bestimmte Art von Fehlern, die durch den Zugriff auf Speicher verursacht werden, der "nicht zu Ihnen gehört". Es ist ein Hilfsmechanismus, der Sie davon abhält, den Speicher zu beschädigen und schwer zu debuggende Speicherfehler einzuführen. Wann immer Sie einen Segfault erhalten, wissen Sie, dass Sie etwas falsch machen mit dem Speicher - Zugriff auf Variablen, die bereits freigegeben wurden, Schreiben in einen schreibgeschützten Teil des Speichers usw. Segmentierungsfehler sind in den meisten Sprachen im Wesentlichen gleich In der Speicherverwaltung gibt es keinen prinzipiellen Unterschied zwischen den Segmentierungen in C und C ++.

Es gibt viele Möglichkeiten, einen segfault zu erhalten, zumindest in den untergeordneten Sprachen wie C (++). Eine gängige Methode zum Abrufen eines Segfault ist die Dereferenzierung eines Nullzeigers:

int *p = NULL;
*p = 1;

Ein weiterer Fehler tritt auf, wenn Sie versuchen, in einen Teil des Speichers zu schreiben, der als schreibgeschützt markiert wurde:

char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault

Dangling Pointer zeigt auf ein Ding, das nicht mehr existiert, wie hier:

char *p = NULL;
{
    char c;
    p = &c;
}
// Now p is dangling

Der Zeiger p hängt, da er auf die Zeichenvariable c , die nach dem Ende des Blocks nicht mehr existiert. Und wenn Sie versuchen, den Dangling-Zeiger (wie *p='A' ) zu dereferenzieren, würden Sie wahrscheinlich einen segfault bekommen.


Um ehrlich zu sein, wie andere Plakate erwähnt haben, hat Wikipedia einen sehr guten Artikel dazu, also schaut mal rein. Dieser Fehlertyp ist sehr häufig und wird oft als "Zugriffsverletzung" oder "Allgemeine Schutzverletzung" bezeichnet.

Sie unterscheiden sich nicht in C, C ++ oder einer anderen Sprache, die Zeiger erlaubt. Diese Art von Fehlern werden normalerweise durch Zeiger verursacht, die sind

  1. Wird vor der korrekten Initialisierung verwendet
  2. Wird nach dem Speicher verwendet, auf den sie zeigen, wurde erneut hinzugefügt oder gelöscht.
  3. Wird in einem indizierten Array verwendet, in dem der Index außerhalb der Array-Grenzen liegt. Dies ist im Allgemeinen nur bei Zeiger-Mathe auf traditionellen Arrays oder C-Strings, nicht auf STL / Boost-basierten Collections (in C ++).

Der Segmentierungsfehler tritt auf, wenn ein Prozess (eine laufende Instanz eines Programms) versucht, auf die schreibgeschützte Speicheradresse oder den Speicherbereich zuzugreifen, der von einem anderen Prozess verwendet wird, oder auf die nicht vorhandene (ungültige) Speicheradresse zuzugreifen. Dangling Reference (Pointer) bedeutet, dass versucht wird, auf ein Objekt oder eine Variable zuzugreifen, deren Inhalt bereits aus dem Speicher gelöscht wurde, z.

int *arr = new int[20];
delete arr;
cout<<arr[1];  //dangling problem occurs here

Segmentierungsfehler werden auch durch Hardwarefehler verursacht, in diesem Fall die RAM-Speicher. Dies ist der seltenere Grund, aber wenn Sie in Ihrem Code keinen Fehler finden, könnte Ihnen vielleicht ein Memtest helfen.

Die Lösung in diesem Fall ändern Sie den RAM.

bearbeiten:

Hier gibt es eine Referenz: Segmentierungsfehler durch Hardware





segmentation-fault