Ich habe oft gehört, dass C spektakulär abstürzen kann. Kürzlich bekam ich meinen ersten Vorgeschmack, als eine Funktion, von der ich erwartete, dass sie eine Saite zurückgab, stattdessen kleine, fröhliche Gesichter zurückgab. Seitdem war ich vorsichtiger beim Initialisieren von Zeigern und beim Mallocing von Speicher für Arrays. Trotzdem habe ich Probleme zu glauben, dass ein Programm so schlimm zusammenbrechen könnte ...
Ich denke, es hängt vom Umfang des Programms ab. Ich meine, wenn ein Fehler in einem Programm, das sich mit deinem Fan befasste, glückliche Gesichter in einen wichtigen Speicherbereich kopiert hat ...?
Meine Frage ist: Wie viel Mythos gibt es in der Welt der spektakulären C-Crashs? Kann ich einige konkrete Beispiele für gefährliche Dinge finden, die man vermeiden sollte?
z.
Das Betriebssystem verhindert die meisten schrecklichen Probleme in diesen Tagen. Das Schlimmste, was ich je getan habe, ist das Festhalten des Rechners (musste nur durch Drücken der Power-Taste neu gestartet werden) und das Scrambeln einiger Dateien.
Alles hängt davon ab, auf welche Ressourcen Sie wirklich zugreifen. Wenn Sie Dateien schreiben, gibt es einige Möglichkeiten, wie sich Verzeichnisstrukturen verwickeln lassen, die Systemdienstprogramme verwirren, aber die meisten dieser Probleme wurden behoben. Wenn Sie etwas als root tun, dann können Sie sicher ein Durcheinander machen, weil viel mehr Systemdateien beschreibbar sind. Wenn Sie das Netzwerk verwenden, gibt es eine Menge Dinge, die mäßig falsch gehen können, aber nicht viel mehr als zu viel Bandbreite zu verbrauchen ist wahrscheinlich. Natürlich, ein paar Jahre Programmierung und Sie werden allerlei unwahrscheinliche Dinge sehen.
In den meisten Fällen ist es jedoch in Ordnung, zu experimentieren und herumzuspielen. Heutzutage sind die Systeme widerstandsfähig genug, dass Sie kein Chaos anrichten, aus dem Sie nicht mehr herauskommen können. Das Betriebssystem behält jedes Programm in seinem eigenen Arbeitsspeicher und verbietet den Zugriff auf ändernde Systeme, es sei denn, Sie sind Administrator / root. Dein Gartenbaum, der baumelnden Zeiger hängt, kann lustige Sachen drucken oder dein Programm abstürzen, aber es wird nicht einen modernen Computer zerstören.
Aus einem Kommentar in einer anderen Antwort: "Ich benutze den Nintendo DS, um sie auszuführen"
Ok, ist wichtig! (Erstens: Tolle Idee! Klingt nach Spaß.) Die Codierung für etwas Ähnliches ist nicht dasselbe, was schiefgehen kann, wie die meisten Programme für einen Desktop-Computer. Ein kurzer Blick auf die Dokumentation für libnds und einige Tutorials zur Nintendo DS-Programmierung zeigt mir, dass es kein Betriebssystem gibt, von dem man sprechen könnte. Also, ich habe keine Ahnung, wie viel du mit einem Streuner machen kannst, wahrscheinlich viel. Möglicherweise etwas schädlich. Es könnte eine gute Idee sein, nach Leuten zu suchen, die schon einmal für diese Plattform programmiert haben, und sehen, was sie zu sagen haben.
Ich denke, dass es in den Tagen vor der virtuellen Erinnerung wahrscheinlich noch schlimmer war, wenn Sie andere Prozessspeicher ausrangieren könnten, aber heutzutage ist das Schlimmste, was passieren kann, das Abstürzen Ihres eigenen Programms. Normalerweise über Segmentierungsfehler von schlechten Zeigern.
Das schließt natürlich Dinge aus, indem Systemressourcen missbraucht werden - Sie können das in jeder Sprache tun.
Als ich C ++ lernen wollte, war es auf einem Mac, auf dem ich 7 oder 8 lief. Ich kann mich nicht erinnern, welches. Wie auch immer, es hatte keinen geschützten virtuellen Speicher, so dass viele Fehler, wie das Zurücklassen eines baumelnden Zeigers oder eines Pufferüberlaufs, den gesamten Computer zum Absturz bringen würden. Ich erinnere mich, dass als Apple zum ersten Mal ankündigte, dass sie ein neues Betriebssystem erstellen wollten, das Speicherplatz auf der Macworld oder ähnlichem hatte, den Quellcode für ein Programm zeigten:
%Vor%Und als sie das Programm starteten und nur das Programm beendet wurde, und nicht die ganze Maschine (es hatte eine Nachricht wie "Sie müssen Ihren Computer nicht neu starten"), brach der ganze Raum voller Entwickler applaudierend in Applaus aus. Wie auch immer, offensichtlich hat das Speichern von Speicher die Programmierung von C oder C ++ wegen der erhöhten Schwere des Absturzes nicht wirklich erschwert.
Heutzutage ist es keine so große Sache, es sei denn, Sie programmieren etwas, das auf Supervisor-Ebene läuft, Sie haben nicht die Fähigkeit, das Betriebssystem zum Absturz zu bringen.
Hier ist ein kurzer Auszug aus Henry Spencers "Zehn Gebote für C-Programmierer":
Für diejenigen, die nicht mit C vertraut sind, denke ich, dass die beste geschriebene Einführung in C von " Die Zehn Gebote für C-Programmierer (Kommentierte Ausgabe) "von Henry Spencer. Die Art, wie es geschrieben ist, vermittelt dem Leser die Gefahren von C ... und ist gleichzeitig lustig (was bedeutet, dass der Leser tatsächlich mehr aufpasst).
==========================
Persönlich ... C stürzt nicht so schlimm ab, wenn Sie Desktop-Entwicklung machen weil Sie den Luxus haben, seg-fault zu betreiben. Seg-Fehler sind wenn das Betriebssystem sieht, dass du versuchst, Dinge wirklich zu machen und es heißt "Hey! Du bist dort nicht erlaubt" und stoppt den Prozess.
Wenn du Embedded C-Entwicklung machst ... dann erhältst du das WIRKLICH spektakuläre, verrückte Zeug ... dh sie VERLANGEN, dass du in 99,9% der Fälle einen Power-Zyklus machst. Wie dieser Zeit, in der der Code irgendwie meinen Callstack durcheinander bringt ... und dann führst du irgendeine zufällige andere Funktion aus ... und dann läuft der ISR irgendwie noch ... und es dauert 2 Wochen, um diesen Fehler zu beheben.
C selbst kann nichts zum Absturz bringen. Sloppy Programmierung kann alles zum Absturz bringen.
Die "glücklichen Gesichter" weisen darauf hin, dass Ihr Code den Speicher beschädigt hat. Das einzige, was C damit zu tun hatte, ist die Tatsache, dass du dich dafür entschieden hast. (Und die Tatsache, dass Ihr Betriebssystem es zugelassen hat, ist überraschend - führen Sie immer noch eine Version von DOS aus?)
Heutzutage ist es ziemlich schwer, C das schwer zum Absturz zu bringen (es sei denn, Sie programmieren einen OS Kernel oder etwas ähnliches).
Zurück in den DOS / Win95 / Win98 Tagen, könntest du ein C-Programm chash wirklich, wirklich schlecht machen. Ich habe das oft verstanden:
Immer wenn ich eine gefährliche Zeigeroperation hatte, die mit der Erinnerung durcheinander kam, bekam ich einen zeichenbasierten Bildschirm voller allerlei Zeichen, in verschiedenen Farben, einige von ihnen, blinzelnd !!! Ich schätze, die Operationen haben sich mit dem Videospeicher vermischt.
Aber heutzutage, da Prozesse in sicheren -Kernen ablaufen, werden Sie das Schlimmste bekommen, wenn Ihr Prozess aufhört.
Vor den Architekturen mit geschütztem Speicher wurden die meisten vom Betriebssystem verwendeten Sprungvektoren auf der Nullseite des Speichers (Adressen beginnend bei Null) gespeichert
Das Schreiben auf Speicherplätze in der Nullseite - einfach mit Null- / Ungültigkeits-Zeigern - würde die Sprungvektoren des Betriebssystems verändern und alle Arten von bizarrem Absturzverhalten verursachen - alles von gesperrten Tastaturen und blinkenden Videobildschirmen voller Müll auf die Festplatte Licht blinkt Raserei, Bluescreen Tod, Neustart usw.
[Kodierung in Assembler hat noch mehr Spaß gemacht]
Wenn Ihr Code auf einem fernmodernen Betriebssystem ausgeführt wird, können Sie glückliche Gesichter nicht in zufällige Punkte im Speicher kopieren. Sie können so oft abstürzen, wie Sie möchten, und es wird nur zur Beendigung Ihres Prozesses führen.
Das nächste Problem, das Sie haben können, besteht darin, Prozessor- / Arbeitsspeicher- / Datenträgerressourcen zu missbrauchen oder so viele Unterprozesse hervorzubringen, dass das Betriebssystem keine PIDs mehr hat (wenn es noch einen 32-Bit-Wert verwendet).
Es gab einen Computer, den Commodore PET 4032 (alias "Fat 40"), wo es tatsächlich möglich war, den Videochip dauerhaft zu brennen, wenn Sie den falschen Wert in den falschen Teil des Speichers steckten. Sie können sich vorstellen, dass, wenn ein C-Compiler auf diesem Computer gewesen wäre, ein wilder Zeiger tatsächlich irreparablen physischen Schaden am Computer verursachen könnte.
Auf jedem Betriebssystem mit geschütztem Speicher ist das schlimmste, was passieren kann, dass Ihr Prozess abstürzt. Nun, wenn Ihr Prozess zufällig Teil des Kernels oder einer Kernel-Erweiterung ist, dann können Sie natürlich das ganze Betriebssystem zum Absturz bringen, aber das ist das Schlimmste, was Sie tun können.
Allerdings ist dies das gleiche mit vielen anderen Sprachen (zum Beispiel in C einen Null-Zeiger, in Java einen Objekt-Verweis, der auf Null gesetzt ist, beide werden Ihren Prozess zum Absturz bringen).
Also, ich glaube, mit geschützem Speicher kann C nicht mehr Schaden anrichten als jede andere Sprache (es sei denn, Ihr Prozess ist Teil des Betriebssystems;))
C lässt Sie mit der Maschine ziemlich direkt umgehen. Wie spektakulär es stürzen kann, ist eine Funktion dessen, was die Maschine tun kann.
Also: Ein Benutzer-Modus-Prozess ohne spezielle Privilegien in einem schönen modernen Betriebssystem wird nicht wirklich so viel tun. Aber Sie haben Software überall. Denken Sie an die Software, die die Bremssysteme in einem Zug steuert. Denken Sie an die Software, auf der die Notfall-Sprechanlage läuft, wenn jemand wirklich Hilfe benötigt. Denken Sie an die Software, die die Zeichen auf einer belebten Autobahn führt. Denken Sie an die Software, die ein Lenkwaffensystem betreibt.
Heutzutage gibt es überall Software. Vieles davon ist in C geschrieben.
Zurück als ich die Win98-Treiber schrieb, verfolgte der BSOD alle. Ich erinnere mich an den folgenden Fehler, den ich gemacht habe
typedef struct _SOME_TAG_ {
%Vor%} MYSTRUCT, * PMYSTRUCT;
.... PMYSTRUCT pMyStruct;
// Und ich benutze diese Struktur, ohne Speicher zuzuweisen ;-) pMyStruct- & gt; nSomeVar = 0;
Und die Fahrerunfälle waren so schrecklich, aber wir hatten ein SoftICE von NUMEGA, obwohl es erst vor 10 Jahren ist. Ich fühle mich wie ewig zurück.
Zurück in der Universität wurde ich beauftragt, einen Multi-Threading-Proxy zu erstellen.
Von Zeit zu Zeit reagierte der Proxy nicht auf die von der Seite abgerufenen Ressourcen. Der Code, der das Problem verursacht:
Ein Code mit Überlaufproblemen, bei dem Variablen in der Nähe eines Dateihandlers verwendet wurden. Bevor ich wusste, was geschah, fand ich es wirklich seltsam, dass das Verschieben der Dateihandler-Deklaration das Problem "repariert" hat, lol.
Ps. check this one (nicht in c, aber eine gute Geschichte :)): Ссылка
Wenn die betreffende Software auf einem PC ausgeführt wird, kann dies "nur" den Computer herunterfahren.
Wenn es jedoch den Betrieb des Motors in Ihrem Auto - oder schlimmer noch, des ABS - steuert, wird nicht nur die Software abstürzen ...
Ein Absturz ist nicht das Schlimmste, was passieren kann.
Ich habe von einem alten Unix-Dateikomprimierungsprogramm gelesen (Sie wissen, wie Zip), das den Rückgabewert von fclose nicht überprüft hat. Ja, fclose kann einen Fehler zurückgeben. Die Ausgabe in eine Datei wird normalerweise gepuffert. Selbst wenn ein Aufruf von fwrite oder putc zu funktionieren scheint und OK zurückgibt, befinden sich die Daten möglicherweise noch in einem Puffer und warten darauf, geschrieben zu werden. Wenn fclose aufgerufen wird, werden alle nicht geschriebenen Daten gelöscht, und dies kann fehlschlagen, da (zum Beispiel) der Datenträger möglicherweise voll ist. Und da das Komprimierungsprogramm normalerweise nur ausgeführt wurde, weil die Platte fast voll war, passierte das ziemlich oft. Also hat das Programm die neue, komprimierte Datei still abgeschnitten, die ursprüngliche unkomprimierte Datei wurde entfernt, und das nächste Jahr oder so, als jemand versuchte, die Datei zu dekomprimieren, fehlte das Ende!
Ich denke, dies ist ein gutes Beispiel dafür, warum das Auslösen von Ausnahmen eine gute Sache sein kann.