Was ist ein Segmentierungsfehler?

Lesezeit: 8 Minuten

Was ist ein Segmentierungsfehler
Rajendra Uppal

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

  • Nur ein Speicherauszug, wenn etwas schief geht!

    – Ergebnisweg

    25. April 2015 um 1:18 Uhr


  • Wird normalerweise aufgerufen, indem versucht wird, einen Nullzeiger zu dereferenzieren, daher ist ein Segmentierungsfehler oft analog zu einem Java NullPointerException.

    – Raedwald

    18. Dezember 2017 um 9:08 Uhr


  • Segmentation kommt von Speichersegmentierung. Sie greifen auf a zu Segment von Erinnerungen, die dir nicht gehören.

    – Kotchwane

    13. Mai 2020 um 10:33 Uhr


1647284414 7 Was ist ein Segmentierungsfehler
Seele

Ein Segmentierungsfehler ist eine bestimmte Art von Fehler, der durch den Zugriff auf Speicher verursacht wird, der „nicht 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 mit dem Speicher falsch machen – Zugriff auf eine bereits freigegebene Variable, Schreiben in einen schreibgeschützten Teil des Speichers usw. Der Segmentierungsfehler ist im Wesentlichen derselbe in den meisten Sprachen, der Sie durcheinander bringen lässt Bei der Speicherverwaltung gibt es keinen prinzipiellen Unterschied zwischen Segfaults in C und C++.

Es gibt viele Möglichkeiten, einen Segfault zu erhalten, zumindest in niedrigeren Sprachen wie C(++). Eine übliche Methode, um einen Segfault zu erhalten, besteht darin, einen Nullzeiger zu dereferenzieren:

int *p = NULL;
*p = 1;

Ein weiterer Segfault 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 etwas, das nicht mehr existiert, wie hier:

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

Der Zeiger p baumelt, weil es auf die Zeichenvariable zeigt c die nach Ende der Sperre nicht mehr existierten. Und wenn Sie versuchen, einen baumelnden Zeiger zu dereferenzieren (wie *p='A'), würden Sie wahrscheinlich einen Segfault erhalten.

  • Das letzte Beispiel ist besonders fies, wenn ich baue: int main() { char *p = 0; { Zeichen c = ‘x’; p = &c; } printf( “%c\n”,*p); 0 zurückgeben; } Entweder mit gcc oder mehreren anderen Compilern ‘scheint’ es zu funktionieren. Keine Warnungen beim Kompilieren. Kein Segfault. Dies liegt daran, dass das ‘}’ außerhalb des Gültigkeitsbereichs die Daten nicht wirklich löscht, sondern sie nur als frei für die erneute Verwendung markiert. Der Code kann jahrelang auf einem Produktionssystem problemlos laufen, Sie ändern einen anderen Teil des Codes, ändern den Compiler oder etwas anderes und BOOOOOM!

    – Chris Huang-Leaver

    13. April 2010 um 9:06 Uhr


  • Entschuldigung für die Beule, aber nur eine Randnotiz … keines Ihrer Beispiele verursacht unbedingt einen Segfault, tatsächlich ist es nur ein undefiniertes Verhalten 😉

    – obataku

    15. September 2012 um 3:01 Uhr

  • @oldrinb: Es ist unmöglich, das zu schreiben Notwendig verursacht einen Segfault. Nicht zuletzt, weil es Systeme gibt, die ohne Speicherschutz arbeiten, also nicht erkennen können, ob ein Stück Speicher tatsächlich „ihm gehört“, und somit weiß nicht Segfaults, nur undefiniertes Verhalten … (z. B. klassisches AmigaOS)

    – DevSolar

    29. Mai 2014 um 18:03 Uhr


  • @ChrisHuang-Leaver, das musst du verstehen c lokal ist, bedeutet dies, dass es danach auf den Stack geschoben wurde { und danach herausgesprungen }. Der baumelnde Zeiger ist nur ein Verweis auf einen Offset, der sich jetzt außerhalb des Stapels befindet. Aus diesem Grund wird das Ändern in einem einfachen Programm niemals einen Segfault auslösen. Andererseits kann es in einem komplexeren Anwendungsfall zu einem Segfault führen, in dem andere Funktionsaufrufe dazu führen könnten, dass der Stack wächst und die Daten enthält, auf die der baumelnde Zeiger zeigt. Schreiben in diese Daten (lokale Variablen) würde zu undefiniertem Verhalten führen (segfault &Co)

    – Ayman Khamouma

    19. Januar 2016 um 21:23 Uhr


  • @ChrisHuang-Leaver, normalerweise muss der Compiler, wenn Sie den Gültigkeitsbereich verlassen, etwas Stack-Speicherplatz wiederherstellen, um den nicht verwendeten Stack-Speicherplatz freizugeben, aber dies geschieht nicht immer (wobei gcc einer dieser Compiler ist). Außerdem wird der zugewiesene Stack-Speicherplatz normalerweise wiederverwendet, daher habe ich von keinem Betriebssystem gehört, das unbenutzte Stack-Seiten an das System zurückgibt und diesen Speicherplatz für a SIGSEGValso erwarte ich kein solches Signal vom Verstümmeln mit dem Stack.

    – Luis Colorado

    22. Juli 2016 um 11:59 Uhr

1647284415 579 Was ist ein Segmentierungsfehler
konrad.kruczynski

Es wäre erwähnenswert, dass der Segmentierungsfehler nicht durch den direkten Zugriff auf einen anderen Prozessspeicher verursacht wird (das höre ich manchmal), da dies einfach nicht möglich ist. Mit virtuellem Speicher hat jeder Prozess seinen eigenen virtuellen Adressraum und es gibt keine Möglichkeit, mit einem Zeigerwert auf einen anderen zuzugreifen. Eine Ausnahme davon können gemeinsam genutzte Bibliotheken sein, bei denen es sich um denselben physischen Adressraum handelt, der (möglicherweise) unterschiedlichen virtuellen Adressen und Kernelspeicher zugeordnet ist, der sogar in jedem Prozess auf die gleiche Weise zugeordnet wird (um zu vermeiden, dass TLB beim Systemaufruf gelöscht wird, denke ich). Und Dinge wie shmat 😉 – das zähle ich als ‘indirekten’ Zugang. Man kann jedoch überprüfen, ob sie sich normalerweise weit entfernt vom Prozesscode befinden und wir normalerweise auf sie zugreifen können (deshalb sind sie dort, dennoch führt ein unsachgemäßer Zugriff auf sie zu einem Segmentierungsfehler).

Dennoch kann ein Segmentierungsfehler auftreten, wenn auf unangemessene Weise auf unseren eigenen (Prozess-)Speicher zugegriffen wird (z. B. wenn versucht wird, in einen nicht beschreibbaren Bereich zu schreiben). Aber der häufigste Grund dafür ist der Zugriff auf den Teil des virtuellen Adressraums nicht abgebildet zu körperlichen überhaupt.

Und das alles in Bezug auf virtuelle Speichersysteme.

  • Mit Shared Memory/Memory Mapped Files ist es möglich, dass jemand anderes mit Ihrem Speicher herumspielt. In WIN32 gibt es auch fiese APIs wie ‘WriteProcessMemory’!

    – paulm

    17. Februar 2014 um 23:46 Uhr

  • @paulm: Ja, ich weiß. Daran hatte ich in “Und Dinge wie Shmat 😉 – das zähle ich als ‘indirekten’ Zugang” im Sinn.

    – konrad.kruczynski

    18. Februar 2014 um 10:08 Uhr

  • In einem Betriebssystem mit virtuellem Speicher gibt es keine Möglichkeit (normalerweise, also bitte, Betriebssystemimplementierer, beschuldigen Sie mich nicht dafür), dass ein Prozess auf den virtuellen Speicher eines anderen Prozesses zugreift, da es sich nicht um eine Art Systemaufruf zum Anfügen von Speicher handelt, der dies zulässt betreten. Virtuelle Speicheradressen haben normalerweise je nach betrachtetem Prozess unterschiedliche Bedeutungen.

    – Luis Colorado

    22. Juli 2016 um 12:02 Uhr

Ein Segmentierungsfehler wird durch eine Anforderung für eine Seite verursacht, die der Prozess nicht in seiner Deskriptortabelle aufgelistet hat, oder durch eine ungültige Anforderung für eine Seite, die er aufgelistet hat (z. B. eine Schreibanforderung auf einer Nur-Lese-Seite).

Ein freier Zeiger ist ein Zeiger, der auf eine gültige Seite zeigen kann oder nicht, aber auf ein “unerwartetes” Speichersegment zeigt.

  • Das stimmt, aber würde es Ihnen wirklich helfen, wenn Sie nicht bereits wüssten, was ein Segmentierungsfehler ist?

    – zoll

    27. Februar 2010 um 9:37 Uhr

Um ehrlich zu sein, hat Wikipedia einen sehr guten Artikel dazu, wie andere Poster bereits erwähnt haben also schau mal dort. Diese Art von Fehler ist sehr häufig und wird oft auch als „Zugriffsverletzung“ oder „Allgemeine Schutzverletzung“ bezeichnet.

Sie unterscheiden sich nicht in C, C++ oder jeder anderen Sprache, die Zeiger zulässt. Diese Art von Fehlern werden normalerweise durch Zeiger verursacht, die sind

  1. Wird vor der ordnungsgemäßen Initialisierung verwendet
  2. Wird verwendet, nachdem der Speicher, auf den sie zeigen, neu zugewiesen oder gelöscht wurde.
  3. Wird in einem indizierten Array verwendet, bei dem der Index außerhalb der Array-Grenzen liegt. Dies ist im Allgemeinen nur der Fall, wenn Sie Zeigerberechnungen für herkömmliche Arrays oder C-Strings durchführen, nicht für STL / Boost-basierte Sammlungen (in C ++).

Was ist ein Segmentierungsfehler
Orhan Cinar

Entsprechend Wikipedia:

Ein Segmentierungsfehler tritt auf, wenn ein Programm versucht, auf eine Speicherstelle zuzugreifen, auf die es nicht zugreifen darf, oder versucht, auf eine nicht erlaubte Weise auf eine Speicherstelle zuzugreifen (z um einen Teil des Betriebssystems zu überschreiben).

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

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

bearbeiten:

Hier gibt es einen Hinweis: Segmentierungsfehler durch Hardware

1647284416 848 Was ist ein Segmentierungsfehler
Jamal

Wikipedias Segmentierungsfehler Seite hat eine sehr schöne Beschreibung darüber, die nur auf die Ursachen und Gründe hinweist. Schauen Sie ins Wiki für eine detaillierte Beschreibung.

Beim Rechnen ist ein Segmentierungsfehler (oft als Segfault abgekürzt) oder eine Zugriffsverletzung 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:

  • Dereferenzieren von NULL-Zeigern – dies ist ein Sonderfall der Speicherverwaltungshardware
  • Versuch, auf eine nicht vorhandene Speicheradresse zuzugreifen (außerhalb des Adressraums des Prozesses)
  • Versuch, auf Speicher zuzugreifen, für den das Programm keine Rechte hat (z. B. Kernelstrukturen im Prozesskontext)
  • Versuch, Nur-Lese-Speicher (z. B. Codesegment) zu schreiben

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

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

  • Dereferenzieren oder Zuweisen zu einem freigegebenen Zeiger (hängender Zeiger, der auf freigegebenen/freigegebenen/gelöschten Speicher zeigt)

  • Ein Pufferüberlauf.

  • Ein Stapelüberlauf.

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

1002800cookie-checkWas ist ein Segmentierungsfehler?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy