- Beim wiederholten Kompilieren und Ausführen eines C-Programms mit
entrstürztehellozwar abnormal ab, aber die MeldungSegmentation faulterschien nach der Compiler-Ausgabe nicht - Diese Meldung wird nicht vom abgestürzten Programm selbst ausgegeben, sondern von der übergeordneten Shell, die den Kindprozess einsammelt und dessen Beendigung durch
SIGSEGVfeststellt - Selbst wenn man
bash -cexplizit angibt, kann Bash, falls effektiv nur noch ein einziger Befehl übrig ist, sich perexecveselbst ersetzen, statt einen neuen Prozess zu erzeugen, sodass keine übergeordnete Shell mehr da ist, die die Meldung ausgeben könnte - In einem separaten Skript startet die per Shebang aufgerufene Bash
./helloals Kindprozess und wartet darauf, erkennt alsoSIGSEGVund gibtSegmentation fault (core dumped)aus - Führt man
./helloin einer Subshell(./hello)aus oder hängt; truean, sodass noch Folgearbeit übrig bleibt, lässt sich dieexec-Optimierung verhindern und die Fehlermeldung wieder sichtbar machen
Der Ausführungspfad, auf dem die Meldung verschwindet
-
Mit folgendem
entr-Befehl werden Kompilierung und Ausführung jedes Mal wiederholt, wenn sichhello.cändertls hello.c | entr -s "gcc -o hello hello.c && ./hello" -
Obwohl
hellomit einem Segmentation Fault beendet wurde, erschienen weder eineSegmentation fault-Meldung noch ein sichtbar von null abweichender Exit-Status — es blieb überhaupt keine Ausgabe zurück -
Auch wenn man den Befehl mit
bash -cumschließt, bleibt das Ergebnis gleichls hello.c | entr -s "bash -c 'gcc -o hello hello.c && ./hello'" -
Verschiebt man denselben Befehl dagegen in
run.shund führt ihn aus, wird der Fehler angezeigt#!/bin/bash gcc -o hello hello.c && ./hellols hello.c | entr -s ./run.sh ./run.sh: line 2: 104465 Segmentation fault (core dumped) ./hello -
Wer
Segmentation faulteigentlich ausgibt- Das abgestürzte Programm ist zu diesem Zeitpunkt bereits beendet; die übergeordnete Shell sammelt den Kindprozess ein und gibt die Meldung erst aus, nachdem sie festgestellt hat, dass er durch
SIGSEGVgestorben ist - Wenn also keine übergeordnete Shell übrig bleibt, die die Meldung ausgeben kann, erscheint gar nichts
- In
bash -c "some_command"kann Bash, wenn effektiv nur noch genau dieser Befehl auszuführen ist, statt eines Forks sich perexecveselbst ersetzen - Diese Optimierung bleibt bei den meisten Ausführungen nach außen unsichtbar
- Beim Skript-Ansatz startet
entr./run.shals Kindprozess, und der Shebang startet eine neue Bash - Diese neue Bash führt nach
gccein Fork für./helloaus und wartet darauf; deshalb kann sie dessen Beendigung durchSIGSEGVerkennen und die Fehlermeldung ausgeben
- Das abgestürzte Programm ist zu diesem Zeitpunkt bereits beendet; die übergeordnete Shell sammelt den Kindprozess ein und gibt die Meldung erst aus, nachdem sie festgestellt hat, dass er durch
Zwei Wege, die übergeordnete Shell zu erhalten
- Führt man den abstürzenden Befehl in einer Subshell aus, erscheint die Meldung wieder
ls hello.c | entr -s "gcc -o hello hello.c && (./hello)" hello.c: line 1: 106595 Segmentation fault (core dumped) ( ./hello )- Die Klammern erzwingen, dass
./helloin einer geforkten Subshell ausgeführt wird - Dadurch bleibt Bash in der Elternrolle und kann das Ende der Subshell durch
SIGSEGVeinsammeln und die Meldung ausgeben
- Die Klammern erzwingen, dass
- Auch wenn nach dem abstürzenden Befehl noch weitere Arbeit übrig bleibt, lässt sich die
exec-Optimierung verhindernls hello.c | entr -s "bash -c 'gcc -o hello hello.c && ./hello; true'" bash: line 1: 109516 Segmentation fault (core dumped) ./hello- Wegen
; truehat Bash nach dem Ende von./hellonoch etwas zu tun und ersetzt sich deshalb nicht selbst durch dieses Programm - So lässt sich die Segmentation-Fault-Meldung auch ohne separates Wrapper-Skript sichtbar machen
- Wegen
1 Kommentare
Lobste.rs-Meinungen
Bei aktuellen Linux-Distributionen sind Core Dumps standardmäßig deaktiviert, was oft lästig ist
Mit
ulimit -c unlimitedkann man sie wieder aktivieren, aber die Core-Datei scheint dann auch nicht im selben Verzeichnis wie die ausführbare Datei zu landen, und es wirkt so, als würde systemd sie irgendwohin verschiebenEs wäre schön, wenn Core Dumps wie bei OpenBSD standardmäßig aktiviert wären und im selben Verzeichnis wie die ausführbare Datei lägen, aber derzeit muss man bei einem Absturz die ausführbare Datei meist erneut in
gdbstartencoredumpctldie letzten Core Dumps auflisten und abrufenMan würde kaum erwarten, einen Core Dump etwa in
/usr/binzu suchen, und solche Orte liegen oft auf kleinen oder schreibgeschützten DateisystemenAls Standardort wäre das Arbeitsverzeichnis nicht deutlich besser?
Selbst wenn Benutzer Core-Dateien aktivieren, wird offenbar angenommen, dass sie trotzdem nicht wissen, was sie tun, sodass sie an einem selbst für root schwer auffindbaren Ort versteckt werden
Wenn man Programme in C oder D schreibt und wissen will, warum sie beendet wurden, sollte man den Rückgabewert des Systemaufrufs
waitprüfen; daran lässt sich erkennen, ob ein Programm durch ein Signal beendet wurdeWenn das Betriebssystem Core Dumps an einen anderen Ort weiterleitet, hat das auch den Vorteil, dass man bei Bedarf sofort debuggen oder der Distribution einen Fehlerbericht schicken kann
Der Linux-Kernel liest beim Erzeugen eines Core Dumps die spezielle Datei
/proc/sys/kernel/core_pattern, um den Speicherort festzulegenStatt in eine Datei zu schreiben, kann er die Daten auch an ein Programm pipen, sodass etwa ein GUI-Dialog angezeigt, ein Debugger sofort gestartet oder ein Bericht per E-Mail an Entwickler gesendet werden kann
systemd setzt den
core_patterndes Kernels auf einen von ihm verwalteten Wert, aber dieselbe Kernel-Funktion lässt sich auch ohne systemd nutzenEs gibt auch die Geschichte, dass während der Entwicklung von Windows XP Core Dumps an Microsoft gesendet wurden und dadurch viele Fehler behoben werden konnten, von deren Existenz man sonst nie erfahren hätte; und wenn auf Windows Entwicklungswerkzeuge installiert sind, ist der bedarfsorientierte Debugger beim Entwickeln eigener Programme recht nützlich
Diese Funktion wurde 2003 in Linux eingeführt; Details stehen in
man 5 coreCore Dumps sind fürs Debugging großartig, können normale Benutzer aber verwirren, wenn sie neben scheinbar nicht zusammengehörigen Dateien liegen, und als System für Diagnoseberichte können sie furchtbar sein
Ich war schockiert, als ich zum ersten Mal sah, wie viele Daten in eingereichten Windows-Absturzberichten enthalten sind
Wenn man ein datenschutzfreundliches Absturzmeldesystem voraussetzt, muss man lernen, die Ursache allein aus Stack- und Registerinformationen herzuleiten, damit eingereichte Abstürze diagnostiziert werden können
Dass Bash Befehle in Skripten manchmal direkt per
execausführt, wusste ich überhaupt nicht; das ist eine überraschende FunktionDa der Overhead des Bash-Prozesses selbst nicht besonders groß ist und ich dort, wo es nötig ist, ohnehin gewohnheitsmäßig
execverwende, wirkt das auf mich wie eine etwas schlecht entworfene FunktionAllerdings könnte es in der Summe aller Ausführungen doch einen größeren Unterschied machen, als man erwarten würde