Segmentationsschuld

Eine Segmentationsschuld (häufig verkürzt zu segfault), Busfehler oder Zugriffsübertretung ist allgemein ein Versuch, auf Gedächtnis zuzugreifen, das die Zentraleinheit nicht physisch richten kann. Es kommt vor, wenn die Hardware ein Betriebssystem über eine Speicherzugriffsübertretung bekannt gibt. Der OS Kern sendet dann ein Signal zum Prozess, der die Ausnahme verursacht hat. Standardmäßig lädt der Prozess, der das Signal erhält, Kern ab und endet. Der Verzug-Signaldressierer kann auch überritten werden, um kundengerecht anzufertigen, wie das Signal behandelt wird.

Busfehler

Busfehlern wird gewöhnlich mit dem SIGBUS-Signal Zeichen gegeben, aber SIGBUS kann auch durch jede allgemeine Gerät-Schuld verursacht werden, dass der Computer entdeckt. Ein Busfehler bedeutet selten, dass die Computerhardware physisch gebrochen wird — wird es normalerweise von einem Programmfehler in einem Quellcode eines Programms verursacht.

Es gibt zwei Hauptursachen von Busfehlern:

nicht existierende Adresse: Die Zentraleinheit wird durch die Software beauftragt, eine spezifische physische Speicheradresse zu lesen oder zu schreiben. Entsprechend setzt die Zentraleinheit diese physische Adresse auf seinem Adressbus und bittet ganze andere mit der Zentraleinheit verbundene Hardware, mit den Ergebnissen zu erwidern, wenn sie für diese spezifische Adresse antworten. Wenn keine andere Hardware antwortet, erhebt die Zentraleinheit eine Ausnahme, feststellend, dass die gebetene physische Adresse durch das ganze Computersystem unerkannt ist. Bemerken Sie, dass das nur physische Speicheradressen bedeckt. Wie man allgemein betrachtet, ist das Versuchen, auf eine unbestimmte virtuelle Speicheradresse zuzugreifen, eine Segmentationsschuld aber nicht ein Busfehler, obwohl, wenn der MMU getrennt ist, der Verarbeiter den Unterschied nicht erzählen kann.

unausgerichteter Zugang: Die Meisten Zentraleinheiten sind Byte-addressable, wo sich jede einzigartige Speicheradresse auf ein 8-Bit-Byte bezieht. Die meisten Zentraleinheiten können auf individuelle Bytes von jeder Speicheradresse zugreifen, aber sie können allgemein auf größere Einheiten (16 Bit, 32 Bit, 64 Bit und so weiter) ohne diese Einheiten nicht zugreifen, die zu einer spezifischen Grenze "ausrichten" werden. Zum Beispiel, wenn Mehrbyte-Zugänge 16 Bit-ausgerichtete sein müssen, würden Adressen (gegeben in Bytes) an 0, 2, 4, und so weiter ausgerichtet und deshalb zugänglich betrachtet, während Adressen 1, 3, 5, und so weiter unausgerichtet betrachtet würden. Ähnlich, wenn Mehrbyte-Zugänge ausgerichtete 32 Bit sein müssen, würden Adressen 0, 4, 8, 12, und so weiter ausgerichtet und deshalb zugänglich betrachtet, und alle Adressen würden zwischen unausgerichtet betrachtet. Der Versuch, auf eine Einheit zuzugreifen, die größer ist als ein Byte an einer unausgerichteten Adresse, kann einen Busfehler verursachen.

Zentraleinheiten allgemein Zugriffsdaten an der vollen Breite ihres Datenbusses zu jeder Zeit. Um Bytes zu richten, greifen sie auf Gedächtnis an der vollen Breite ihres Datenbusses, dann Maske zu und bewegen sich, um das individuelle Byte zu richten. Das ist ineffizient, aber geduldet, weil es eine wesentliche Eigenschaft für den grössten Teil der Software ist, spannen Sie besonders Verarbeitung. Verschieden von Bytes können größere Einheiten zwei ausgerichtete Adressen abmessen und würden so mehr als einen Abruf auf dem Datenbus verlangen. Es ist für Zentraleinheiten möglich, das zu unterstützen, aber diese Funktionalität ist direkt am Maschinencodeniveau selten erforderlich, so vermeiden Zentraleinheitsentwerfer normalerweise, es durchzuführen, und geben stattdessen Busfehler für den unausgerichteten Speicherzugang aus.

Übertretung der Schuld/Zugangs der Segmentation/Seite

Eine Segmentationsschuld kommt vor, wenn ein Programm versucht, auf eine Speicherposition zuzugreifen, die ihm dem Zugang nicht erlaubt wird oder versucht, auf eine Speicherposition in einem Weg zuzugreifen, dem (zum Beispiel nicht erlaubt wird, versuchend, einer Read-Only-Position zu schreiben, oder einen Teil des Betriebssystems zu überschreiben).

Segmentation ist eine Annäherung an das Speichermanagement und Schutz im Betriebssystem. Es ist durch die Paginierung zu den meisten Zwecken ersetzt worden, aber viel von der Fachsprache der Segmentation wird noch, "Segmentationsschuld verwendet" ein Beispiel zu sein. Einige Betriebssysteme haben noch Segmentation an einem logischen Niveau, obwohl Paginierung als die Hauptspeicherverwaltungspolitik verwendet wird.

Auf Unix ähnlichen Betriebssystemen wird ein Signal genannt SIGSEGV an einen Prozess gesandt, der auf eine ungültige Speicheradresse zugreift. Auf Windows von Microsoft, ein Prozess, dass Zugriffsinvalide-Gedächtnis die STATUS_ACCESS_VIOLATION Ausnahme erhält.

Häufige Gründe

Segmentationsschuld

Einige Ursachen einer Segmentationsschuld können wie folgt zusammengefasst werden:

  • der Versuch, ein Programm durchzuführen, das richtig nicht kompiliert. Bemerken Sie, dass die meisten Bearbeiter nicht Produktion eine Dualzahl gegeben ein Übersetzungszeit-Fehler werden.
  • eine Pufferüberschwemmung.
  • das Verwenden uninitialisierter Zeigestöcke.
  • dereferencing UNGÜLTIGE Zeigestöcke.
wenn es
  • versucht, auf Gedächtnis zuzugreifen, bekennt sich das Programm nicht.
wenn es
  • versucht, Gedächtnis zu verändern, bekennt sich das Programm (Lagerungsübertretung) nicht.
  • das Übersteigen der zulässigen Stapel-Größe (vielleicht wegen flüchtigen recursion oder einer unendlichen Schleife)

Allgemein kommen Segmentationsschulden vor, weil ein Zeigestock UNGÜLTIG ist, oder weil er zum zufälligen Gedächtnis (wahrscheinlich nie initialisiert zu irgendetwas) hinweist, oder weil er zum Gedächtnis hinweist, das freed/deallocated / "gelöscht" gewesen ist.

z.B.

Rotforelle *p1 = UNGÜLTIG;//Initialisiert zur Null, die OK, ist

//(aber kann nicht dereferenced auf vielen Systemen sein).

Rotforelle *p2;//Nicht initialisiert überhaupt.

Rotforelle *p3 = neue Rotforelle [20];//Groß! es, wird zugeteilt

löschen Sie [] p3;//, aber jetzt ist es nicht mehr.

</Quelle>

Jetzt, dereferencing einige dieser Variablen konnte eine Segmentationsschuld verursachen.

Beispiele

Busfehlerbeispiel

Das ist ein Beispiel des unausgerichteten Speicherzugangs, der auf der C Programmiersprache mit AT&T Zusammenbau-Syntax geschrieben ist.

  1. einschließen

int Hauptsache (interne Nummer argc, Rotforelle ** argv) {\

interne Nummer *iptr;

Rotforelle *cptr;

  1. wenn definiert (__ GNUC __)
  2. wenn definiert (__ i386 __)

/* Ermöglichen Sie Anordnungsüberprüfung auf x86 * /

__ asm __ ("pushf\norl 0 $ x40000, (%esp) \npopf");

  1. elif definiert (__ x86_64 __)

/* Ermöglichen Sie Anordnungsüberprüfung auf x86_64 * /

__ asm __ ("pushf\norl 0 $ x40000, (%rsp) \npopf");

  1. endif
  2. endif

/* malloc stellt immer ausgerichtetes Gedächtnis * / zur Verfügung

cptr = malloc (sizeof (interne Nummer) + 1);

/* Erhöhen Sie den Zeigestock durch einen, es falsch ausgerichtet * / machend

iptr = (interne Nummer *) ++ cptr;

/* Dereference es als ein int Zeigestock, einen unausgerichteten Zugang * / verursachend

*iptr = 42;

kehren Sie 0 zurück;

}\

</Quelle>

Das Kompilieren und das Laufen des Beispiels auf Linux auf x86 demonstrieren den Fehler:

$ gcc-ansi sigbus.c-o sigbus

$./sigbus

Busfehler

$ gdb./sigbus

(gdb) r

Empfangenes

Programm-Signal SIGBUS, Busfehler.

0x080483ba im wichtigen

(gdb) x/i $pc

0x80483ba

(gdb) p/x $eax

1 $ = 0x804a009

(gdb) p/t $eax & (sizeof (interne Nummer) - 1)

2 $ = 1

</Code>

Das GDB Testhilfeprogramm zeigt, dass der unmittelbare Wert 0x2a an der im EAX-Register versorgten Position mit der X86 Zusammenbau-Sprache versorgt wird. Das ist ein Beispiel des Registers das indirekte Wenden.

Der Druck der niedrigen Ordnungsbit der Adresse zeigt, dass es zu einer Wortgrenze ("dword" nicht ausgerichtet wird, x86 Fachsprache verwendend).

Segmentationsschuld-Beispiel

Hier ist ein Beispiel von ANSI C Code, der eine Segmentationsschuld auf Plattformen mit dem Speicherschutz schaffen sollte:

int Haupt(Leere)

{\

Rotforelle *s = "hallo Welt";

*s = 'H';

}\

</Quelle>

Wenn das Programm, das diesen Code enthält, die Schnur "hallo kompiliert wird, wird Welt" in die Abteilung des Programms rechtskräftige Datei gekennzeichnet als read-only-gelegt; wenn geladen, legt das Betriebssystem es mit anderen Schnuren und unveränderlichen Daten in einem Read-Only-Segment des Gedächtnisses. Wenn durchgeführt, wird eine Variable, s, veranlasst, zur Position der Schnur hinzuweisen, und ein Versuch wird gemacht, einen H Charakter durch die Variable ins Gedächtnis zu schreiben, eine Segmentationsschuld verursachend. Wenn es solch ein Programm mit einem Bearbeiter kompiliert, der für die Anweisung von Read-Only-Positionen während der Übersetzung nicht überprüft, und das Laufen davon auf einem Unix ähnlichen Betriebssystem erzeugt den folgenden Laufzeitfehler:

$ gcc segfault.c-g-o segfault

$./segfault

Segmentationsschuld</Code>

Backtrace der Kerndatei von gdb:

Empfangenes

Programm-Signal SIGSEGV, Segmentationsschuld.

0x1c0005c2 im wichtigen an segfault.c:6

6 *s = 'H';

</Code>

Die Bedingungen, unter denen Segmentationsübertretungen vorkommen, und wie sie sich äußern, sind zu einem Betriebssystem spezifisch.

Weil ein sehr allgemeiner Programm-Fehler ein ungültiger Zeigestock dereference ist (ein gelesener oder schreiben Sie durch einen ungültigen Zeigestock, der in C verwendet ist, um "Zeigestock zu keinem Gegenstand" und als ein Fehlerhinweis zu bedeuten), stellen am meisten Betriebssysteme die solche Adresse des ungültigen Zeigestocks kartografisch dar, dass das Zugreifen darauf eine Segmentationsschuld verursacht.

interne Nummer *ptr = UNGÜLTIG;

*ptr = 1;

</Quelle>

Dieser Beispielcode schafft einen ungültigen Zeigestock und versucht, einen Wert seinem nicht existierenden Ziel zuzuteilen. Das Tun verursacht so eine Segmentationsschuld an der Durchlaufzeit auf vielen Betriebssystemen.

Ein anderes Beispiel ist recursion ohne einen Grundfall:

int Haupt(Leere) {\

wichtig ;

kehren Sie 0 zurück; }\</Quelle>

der den Stapel veranlasst überzufließen, der auf eine Segmentationsschuld hinausläuft. Bemerken Sie, dass unendlicher recursion auf keine Stapel-Überschwemmung abhängig von der Sprache, Optimierungen notwendigerweise hinauslaufen kann, die durch den Bearbeiter und die genaue Struktur eines Codes durchgeführt sind. In diesem Fall ist das Verhalten des unerreichbaren Codes (die Rückbehauptung) unbestimmt, so kann der Bearbeiter es beseitigen und eine Schwanz-Anruf-Optimierung verwenden, die auf keinen Stapel-Gebrauch hinauslaufen könnte. Andere Optimierungen konnten das Übersetzen des recursion in die Wiederholung einschließen, die gegeben die Struktur der Beispiel-Funktion auf das Programm hinauslaufen würde, das für immer, wahrscheinlich läuft sie hat seinen Stapel nicht überflutet.

Siehe auch

Links


SLD / Quelltrennung
Impressum & Datenschutz