Elegant terminieren
Am Ende
Viele Gedanken machen sich die meisten Entwickler, wie ihre Software startet und abläuft. Dabei hinterlassen Programme vor dem Gang an die Schrottpresse in ihrem Testament noch manch nützliche Botschaft.
Viele Gedanken machen sich die meisten Entwickler, wie ihre Software startet und abläuft. Dabei hinterlassen Programme vor dem Gang an die Schrottpresse in ihrem Testament noch manch nützliche Botschaft.
Zwei Gründe führen dazu, dass Programmcode endet: Entweder hat er seine vorgesehene Aufgabe erfüllt und es gibt keinen Code mehr, der auszuführen wäre. Dazu zählt auch die bewusste Entscheidung eines Anwenders, das Programm zu beenden, etwa über einen Menüpunkt »Datei | Schließen«
. Diese einfache Erkenntnis ist insofern bemerkenswert, weil Lehrbücher immer noch vom EVA-Prinzip (Eingabe, Verarbeitung, Ausgabe) sprechen. Manche Shelltools, darunter »grep«
oder »sed«
mögen noch diesem Paradigma folgen, bei komplexeren Anwendungen wie Firefox, Wireshark oder einer Web-basierten Lohnbuchhaltung sind diese Schritte schwieriger zu erkennen. Aber auch sie terminieren bisweilen aus einem anderen, dem zweiten Grund: wegen Fehlern.
Eine frühere "Programmieren"-Einführung kritisierte den zu gedankenlosen Einsatz von Exceptions: Das bequeme Sprachmittel der Ausnahmen verlagert die Fehlerbehandlung an eine zentrale Stelle [1]. Dabei sollten sie jedoch nicht als gesellschaftlich akzeptiertere Version von »goto«
missbraucht werden. Magazin-Leser Hartmut Goebel rettete daraufhin die Ehre der Exceptions, indem er auf den geringeren Code-Overhead des Konstrukts hinwies.
Zu welchem Lager der Ausnahmebehandlungen ein Entwickler sich auch zählt, er muss sich mit der Frage beschäftigen, ob und wie er ein Programm bei schwerwiegenden Fehlern beendet. Dazu hat er nämlich eine ganze Reihe von Optionen: Endet irgendwann der Quelltext, springt der Kontrollfluss quasi über die Klippe – das Programm terminiert.
Tatsächlich kümmern sich der Interpreter oder Compiler oft noch ums Recycling: Diese oder dazugelinkte Funktionen schließen Dateideskriptoren, um zu gewährleisten, dass laut Programmlogik bereits geschriebene Daten auch wirklich auf der Festplatte landen. Sie informieren den Netzwerkstack, um noch offene TCP/IP-Verbindungen abzubauen, sodass der Kommunikationspartner auch vom Programmende erfährt, und erledigen noch einiges mehr.
Programmierer fahren jedoch sicherer, wenn sie möglichst viele dieser Aufgaben explizit erledigen, denn Bibliotheken, Sprachen und Ablaufumgebung handhaben sie im Detail mitunter unterschiedlich. Die meisten Sprachen bieten eine Bibliotheksfunktion wie beispielsweise »exit()«
an, die einen Großteil des Auszugs organisiert. Ihr geben Entwickler auch einen Rückgabewert mit, den der Kernel als letzte Nachricht des Prozesses an seine Verwandschaft nutzt. Per Konvention gilt im Unix-Universum, dass 0 ein problemloses Programmende signalisiert und andere Werte den jeweiligen Grund für ein Problem anzeigen.
Da zuweilen mehrere Gründe gleichzeitig verantwortlich sind, verwenden Systemtools manchmal Bitmasken und klassifizieren so typischerweise bis zu 32 unterschiedliche Fehler. In der Realität gibt es oft jedoch nur eine schnöde 1 für das Problem "Fehler" und manche Bits verwendet der Kernel für andere Zwecke. Die Standardbibliothek von Linux listet in »/usr/include/asm-generic/errno.h«
rund 130 Problemursachen auf.
Bash-Anwender wissen, dass »$?«
den Returncode abfragt. Auch der Kernel nutzt diese Information und meldet sie dem Vaterprozess über den Prozessstatus. Der Vater erhält ihn beim Aufruf von »wait(&Status);«
, mit dem Makro »WEXITSTATUS(Status)«
erfährt er den Grund für das Programmende. Tröstlich für Prozesse, dass es immer jemanden gibt, der auf sie wartet.
Infos
Umfang: 1 Heftseiten
Preis € 0,99
(inkl. 19% MwSt.)
Alle Rezensionen aus dem Linux-Magazin
Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...