Wie haben sie Segmentierungsfehler vor dem geschützten Speicher behoben?

20

Wenn ich jetzt einen Programmierfehler mit Zeigern in C mache, bekomme ich einen netten Segmentierungsfehler, mein Programm stürzt ab und der Debugger kann mir sogar sagen, wo es schief gegangen ist.

Wie haben sie das gemacht, als kein Speicherschutz verfügbar war? Ich kann sehen, wie ein DOS-Programmierer herumfummelt und das gesamte Betriebssystem abstürzt, wenn er einen Fehler macht. Die Virtualisierung war nicht verfügbar, daher konnte er nur neu starten und es erneut versuchen. Ging es wirklich so?

Bart Friederichs
quelle
4
Ja, so ist es gelaufen. Ein zufälliger Neustart des Computers ist häufig aufgetreten. Speicherschutz ist eine wunderbare Sache :)
Rocklan
7
Wenn Sie keinen geschützten Speicher haben, liegt kein Segmentierungsfehler vor. Selbst wenn Sie einen geschützten Speicher haben, können Sie Ihren eigenen Speicherplatz trotzdem überlasten. Das Betriebssystem kümmert sich einfach nicht darum.
Blrfl
3
Selbst jetzt verursachen viele Zeigerfehler keinen netten Fehler.
CodesInChaos
1
Zum Zeitpunkt von DOS gab es in anderen Betriebssystemen bereits geschützten Speicher.
Mouviciel

Antworten:

36

Ich kann sehen, wie ein DOS-Programmierer herumfummelt und das gesamte Betriebssystem abstürzt, wenn er einen Fehler macht.

Ja, genau das ist passiert. Auf den meisten Systemen mit Speicherzuordnungen wurde Position 0 als ungültig markiert, sodass Nullzeiger leicht erkannt werden konnten, da dies der häufigste Fall war. Aber es gab viele andere Fälle, und sie verursachten Chaos.

Ich möchte Sie darauf hinweisen, dass der derzeitige Fokus auf das Debuggen nicht der Vergangenheit angehört. Bisher wurden viel größere Anstrengungen unternommen, um korrekte Programme zu schreiben, anstatt Fehler aus falschen Programmen zu entfernen. Einiges davon war, weil das unser Ziel war, aber vieles war, weil die Werkzeuge die Dinge schwer machten. Versuchen Sie, Ihre Programme auf Papier oder Lochkarten zu schreiben, nicht in einer IDE und ohne den Vorteil eines interaktiven Debuggers. Es gibt Ihnen einen Vorgeschmack auf Korrektheit.

Ross Patterson
quelle
3
Tatsächlich hoffte ich, dass "alte Knacker" meine Frage beantworten würden. Nichts ist besser als die Erfahrung aus erster Hand. Vielen Dank.
Bart Friederichs
6
Versuchen Sie, Code zu schreiben, wenn die Hardware jeden Abend von 02:00 bis 06:00 Uhr zum Debuggen verfügbar ist, vorausgesetzt natürlich, Ihr Kollege hat ihn nicht für seine Debugsitzung reserviert.
MSalters
@MSalters In der Tat! Bei meinem ersten Job konnten wir auch am Sonntag von 07:00 bis 1900 Slots buchen - ein wahrer Leckerbissen, möchte ich Ihnen sagen :-)
Ross Patterson,
2
Ich erinnere mich, mein erstes Programm auf Papier geschrieben zu haben , als ich von der Universität nach Hause kam.
Am
1
@ JanDoggen, das gleiche für mich. Wenn Sie nur einen Versuch haben, zählt dieser Versuch wirklich.
Nalply
23

Zu meiner Zeit hatten wir keinen Speicherschutz und das ganze schicke Geschäft! Wir haben printf verwendet, um festzustellen, wo wir im Programm waren, und es hat uns gefallen !

Trotz allem bedeutete dies normalerweise, dass wir nur vorsichtiger waren. Wo malloc aufgerufen wird, musste es irgendwo anders im Programm ein freies geben, und eine solche Überprüfung war streng, da Segmentierungsfehler im Falle eines Problems, wie Sie deutlich gezeigt haben, keine hilfreichen Fehler sind.

Im Falle solcher Fehler ist das Beste , was Sie tun könnten versuchen zu verstehen , wenn eine solche Segmentierung Fehler (unter Verwendung von printf) auftreten und Blick auf den Code, festzustellen , warum Zugriff auf den Speicher zu diesem Zeitpunkt von dort nicht gültig und die Arbeit nach hinten war.

Im Wesentlichen passiert heute das Gleiche, außer dass wir Debugger verwenden, um festzustellen, wann Fehler auftreten, aber Sie müssen immer noch verstehen, warum dies passiert ist, und es ist nicht immer so einfach, wie die Zeile zu finden, in der der Fehler aufgetreten ist. Fehler verursachen Fehler wie eine Kettenreaktion, und wenn Sie damals ein C-Programmierer waren, verbrachten Sie 20% Ihrer Zeit mit dem Programmieren und den Rest der Zeit damit, Ihre Haare herauszuziehen, um Fehler zu beheben.

Neil
quelle
2
Befreie die Mallocs!
Chris
1
Von Zeit zu Zeit, sogar heute, sind sogar der Aufrufstapel und der variable Status völlig nutzlos, um festzustellen, was zum Teufel schief gelaufen ist und wie dies behoben werden kann. Dies ist insbesondere dann der Fall, wenn Sie eine komplexe Software mit einer großen Anzahl möglicher Zustände haben, von denen einige voneinander abhängig sind und andere sich gegenseitig ausschließen. Ein einziger Stray Write überall und eine unterlassene Behauptung für die garantierte Voraussetzung können Sie genau dorthin bringen.
ein CVn
1
@ MichaelKjörling, ich denke, was das Erkennen von Fehlern in Programmen betrifft, haben wir nur Fortschritte gemacht, was das Finden des Fehlerauslösers betrifft, aber wir haben noch Meilen vor uns, um die Ursache für diese Fehler zu finden. Behauptungen helfen mir auf jeden Fall, bei Verstand zu bleiben. :)
Neil
6

Gut ..

Ein Segfault ist ein wirklich netter Indikator dafür, dass etwas nicht stimmt, aber Sie müssen immer noch die Grundursache finden. Wenn Sie also die Frage stellen, wie Sie die Ursache finden, ist die Antwort heute nicht viel anders als damals. Natürlich wurde die Arbeit mit den Sprachen und Werkzeugen einfacher, aber die allgemeine Taktik ist dieselbe:

  • Die Protokollierung hilft dabei, den Bereich zu finden, in dem sich Ihr Problem befindet. Die binäre Suche printf ist eine Form davon.
  • Debuggen, Schritt für Schritt, Breakpoints und Uhren
  • Refactoring zum besseren Verständnis
  • starrte hart auf den Code
  • Schauen Sie sich den Speicher- / Core-Dump an
  • Füttere es mit verschiedenen Daten
  • es anderen Leuten zeigen
  • Wechseln Sie zu einer Sprache ohne Zeiger (und einer Reihe neuer Probleme) ...

Auf einer abstrakteren Ebene haben Sie drei Ansätze: 1. Arbeiten Sie mit dem Code. 2. Schauen Sie sich das Programm an, während es ausgeführt wird. 3. Schauen Sie sich die Ergebnisse an, nachdem es etwas Dummes getan hat

Übrigens muss ein Zeigerfehler keinen Segfault erzeugen.

Als Amiga-Programmierer habe ich so ziemlich alles benutzt. Und ja startet wo üblich neu.

openCage
quelle
4

Auf der IBM 360, auf der Fortran-Batch-Jobs ausgeführt wurden, wurden Hex-Core-Dumps erstellt. Solch eine Müllkippe könnte bis zu einem Zoll dickes grün-weißes Druckerpapier sein. Es würde sagen, was die Register waren, und von dort aus konnten wir zurückverfolgen und herausfinden, was das Programm tat. Wir konnten jedes Unterprogramm finden und herausfinden, wo es seine Rücksprungadresse gespeichert hat, damit wir den Kontext sehen konnten. Es wäre hilfreich, eine Assembler-Liste des Programms zu haben.

Mike Dunlavey
quelle
2

Einmal arbeitete ich an der Fehlerbehebung einer damals berühmten Windows 3.1-Präsentationssoftware.

Ich hatte einen Bug, der, als er auftrat, den Blue Screen of Death verursachte.

Der Fehler trat nur auf, wenn eine bestimmte Schleife mehr als 1000 Mal ausgeführt wurde. Ich habe die erweiterten Funktionen des Debuggers verwendet, um einen Haltepunkt 1000 Mal passieren zu lassen, und bin dann vorsichtig durch das Programm gegangen. Jedes Mal, wenn ich zu weit gegangen bin oder einen Funktionsaufruf übersprungen habe, der den Fehler Windows Blue Screened enthielt.

Nach einigen Arbeitstagen habe ich es schließlich auf eine Funktion beschränkt, der der Speicherplatz ausgeht. Statt eine Fehlermeldung anzuzeigen, habe ich die Fehlermeldung an einen Puffer angehängt. Mit jeder nachfolgenden Iteration wurde mehr Speicher gelöscht, bis etwas Entscheidendes überschrieben und Windows gelöscht wurde.

Debugging-Fähigkeiten und Ausdauer waren die Lösung.

Stuart Woodward
quelle