Feb. 2006
Fehlerbehandlung
in Programmiersystemen
Christoph Kessler
Universität Linköping, Schweden
Fehler-Klassifikation
Behandlung statischer Fehler
Behandlung von Laufzeitfehlern
Exception-Konzept
Debugging
Christoph Kessler, IDA,
Linköpings universitet, 2006.
Programmierfehler…
Ein erheblicher Teil der Gesamtkosten eines Softwareprojektes
entfällt auf Testen, Fehlersuche und -behebung.
Welche Fehlertypen können auftreten?
Klassifikation
Prävention, Diagnose, Behandlung
Programmiersprachliche Konzepte
Compiler, IDE
Sonstige Werkzeuge: Debugger, Verifizierer, ...
C. Kessler, IDA, Linköpings universitet.
2
Feb. 2006
Programmierfehler – Klassifikation (1)
Syntaktische Fehler
Syntaxfehler
z.B. vergessenes Semikolon
Semantische Fehler
Statische semantische Fehler
Statische Typfehler
Falscher Parametertyp;
Downcast ohne Laufzeit-Überprüfung
Nicht
deklarierte Variable
Laufzeitfehler
Logische Fehler
Algorithmische Fehler
vergessener Spezialfall,
Nichtterminierung
Akkumulation von Rundungsfehlern
Verletzung geforderter Invarianten
Numerische
Fehler
Kontraktverletzung
C. Kessler, IDA, Linköpings universitet.
3
Feb. 2006
Programmierfehler – Klassifikation (2)
Laufzeitfehler – in der Regel nicht statisch prüfbar
Zugriffsfehler
z.B.:
Arrayindex-Fehler
Index out of bounds
Pointerfehler
Dereferenziere NULL-Pointer
Arithmetische Fehler
Division durch 0, Überlauf
I/O – Fehler
unerwartetes Dateiende
Kommunikationsfehler
Falscher Empfänger, falscher Typ
Synchronisationsfehler
Daten-”race”, deadlock
Ressourcen-Erschöpfung
Speicher, Zeitkonto
...
Bemerkung: Es gibt weitere Fehlertypen, und Kombinationen.
C. Kessler, IDA, Linköpings universitet.
4
Feb. 2006
Gegenmittel:
Prävention, Diagnose, Behandlung
Programmiersprache / Laufzeitsystem
Typsicherheit
statische Typfehler
Exception-Konzept
Laufzeitfehler
Automatische Speicherverwaltung Speicherlecks, Pointerfehler
Compiler-Frontend, IDE
Syntaxfehler, statische semant. Fehler
Programmverifizierer
Kontraktverletzung
Code-Inspektion [Fagan’76] Alle Fehlertypen
Testen und Debuggen
Laufzeitfehler
Laufzeit-Schutzmonitor
Zugriffsfehler
Visualisierer
Kommunikationsfehler,
Synchronisationsfehler
C. Kessler, IDA, Linköpings universitet.
5
Feb. 2006
Exception-Konzept
PL/I (IBM) ca. 1965: ON condition …
J. B. Goodenough, POPL’1975 und Comm. ACM Dez. 1975
In vielen modernen Programmiersprachen unterstützt
CLU, Ada, Modula-3, ML, C++, Java, C#
Überblick:
Fehler vs. Exception
Exception-Propagation
Geprüfte vs. ungeprüfte Exceptions
Implementierung
Exceptions in CORBA
Exceptions und Aspekt-orientierte Programmierung
Zusammenfassung und Literatur
C. Kessler, IDA, Linköpings universitet.
6
Feb. 2006
Exception-Konzept
2 Arten von Laufzeitfehlern:
Fehler (error): im Programm nicht behandelbar, Programmabbruch
Ausnahme (exception): im Programm (teilweise) behandelbar
Ausgelöst (thrown) durch Laufzeitsystem bei erkanntem Laufzeitfehler
oder durch das Programm selbst
Nachricht
Laufzeitobjekt, das eine ungewöhnliche oder Fehlersituation definiert
hat
an das Programm
einen Typ (Exception-Klasse)
kann
Parameter haben, z.B. String mit Klartextmeldung
Auch
benutzerdefinierte Exceptions z.B. für Randfälle
Exception-Handler:
enthält
Code-Block zur Behandlung
ist
statisch assoziiert mit geschütztem Code-Block,
den er im Ausnahmefall ersetzt
C. Kessler, IDA, Linköpings universitet.
7
Feb. 2006
Exception – Beispiel (in Java)
public class class1 {
public static void main ( String[] args ) {
try {
System.out.println("Hallo, " + args[0] );
}
catch (ArrayIndexOutOfBoundsException e ) {
System.out.println("Bitte ein Argument angeben! " + e);
}
System.out.println("Tschuess");
}
}
%
% java
java class1
class1 Christoph
%
javaChristoph
class1
Hallo,
Exception
in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
Bitte
ein Argument angeben! java.lang.ArrayIndexOutOfBoundsException: 0
Tschuess
at class1.main(class1.java:4)
Tschuess
C. Kessler, IDA, Linköpings universitet.
8
Feb. 2006
Propagation von Exceptions
Falls eine Exception nicht in der betroffenen Methode behandelt wird, wird
die Methode verlassen und dieselbe Exception beim Aufrufer ausgelöst,
bis entweder
ein passender Handler gefunden wird, oder
main() verlassen wird (dann Fehlermeldung und Abbruch).
Optionaler finally-Block wird jedoch immer ausgeführt
z.B. zur Rückgabe von Ressourcen
Zu klären:
Wann passt ein Handler?
Wie kann man statisch sicherstellen, dass eine bestimmte Exception
irgendwann behandelt wird?
Implementierung?
C. Kessler, IDA, Linköpings universitet.
9
Feb. 2006
Wann ”passt” ein Handler?
Object
Exception-Klassenhierarchie
Benutzerdefinierte
Exceptions durch Ableiten
Throwable
Error
Exception
RunTimeException
ThreadDeath
VirtualMachineError
ArithmeticException
…
ArrayIndexOutOfBoundsE
NullPointerException
Handler catch( XYException e ) {…}
passt, falls XYException vom
gleichen Typ oder Supertyp der
ausgelösten Exception ist.
C. Kessler, IDA, Linköpings universitet.
IllegalAccessException
NoSuchMethodException
10
…
Feb. 2006
Geprüfte und ungeprüfte Exceptions
Geprüfte (checked) Exception: muss
in einer Methode behandelt, oder
in Methodendeklaration explizit als propagiert gekennzeichnet werden:
void writeEntry( … ) throws IOException { … }
Ungeprüfte (unchecked) Exception: wird implizit propagiert
In Java: Alle Exceptions sind geprüft,
ausser RunTimeException und deren Subtypen.
Geprüfte Exceptions: + Kapselung
+ statische Prüfbarkeit
+ wird Teil des Kontrakts einer Methode
+ geeignet für Komponentensysteme, z.B. CORBA
– Erweiterbarkeit
C. Kessler, IDA, Linköpings universitet.
11
Feb. 2006
void bar(…) {
try { … }
catch(E1 e) {…}
catch(E2 e) {…}
Einfache Lösung:
-> catch(E1)
…
Stack von Handlern
bar: -> catch(E2)
}
Bei Eintritt in geschützten Block (try {…}):
-> catch(…)
Pushe alle seine Handler (catch(…) {…})
foo: -> catch(…)
Bei Auftreten einer Exception:
main: -> catch(…)
Poppe obersten Handler und beginne (Test auf Exceptiontyp).
Falls der nicht passt, löse wieder aus und iteriere.
(Falls letzter Handler in aktueller Methode auch nicht passte,
poppe auch deren Activation record => verlasse Methode.)
Bei normalem Verlassen des try-Blocks: poppe seine Handler
+ einfach
– Overhead (push/pop) auch bei Nichtauftreten einer Exception
Implementierung
Effizientere Lösung:
Compiler erzeugt Tabelle aus Paaren (try-Block, passende Handler)
Auftreten
finde try-Block durch Binärsuche (PC)
Feb. 2006
C. Kessler,
IDA, Bei
Linköpings
universitet. einer Exception: 12
Exceptions in CORBA
CORBA IDL (Interface Definition Language)
erlaubt benutzerdefinierte Exceptions
Sprachunabhängig
Propagation über Fernaufrufe hinweg
// IDL
module BookRepository {
…
interface BorrowableCollection : Collection {
exception Unavailable {
Date when_available;
}
void borrow_book ( in ISBN book_id,
in PersonName borrower,
out Date return_date )
raises ( Unavailable );
};
};
C. Kessler, IDA, Linköpings universitet.
13
Feb. 2006
Exceptions und AOP
Nachteil von Exception-Behandlung:
catch()-Blöcke stören Programmübersicht
Code-Länge
Idee für Java:
Exception-Behandlung als Aspekt ausfaktorisieren,
mit Aspect-J einweben
Systematischer durch generische Exceptionbehandlung
Kompression des Exception-Behandlungscode um ca. 75%
M. Lippert, C. Lopes: A Study on Exception Detection and Handling
using Aspect-Oriented Programming. Proc. ICSE-2000, ACM.
C. Kessler, IDA, Linköpings universitet.
14
Feb. 2006
Zusammenfassung, Literatur
Exceptions
Bewährtes Konzept zur Behandlung von Laufzeitfehlern
Effizient implementierbar
Geeignet für komponentenbasierte Softwareentwicklung
M. Scott: Programming Language Pragmatics. Morgan Kaufmann, 2000.
Abschnitt 8.5 über Exception Handling.
J. Goodenough: Structured Exception Handling. ACM POPL, Jan. 1975
J. Goodenough: Exception Handling: Issues and a proposed notation.
Communications of the ACM, Dec. 1975
B. Ryder, M. Soffa: Influences on the Design of Exception Handling, 2003
Konferenzen ACM POPL und OOPSLA
C. Kessler, IDA, Linköpings universitet.
15
Feb. 2006
Feb. 2006
Debugging
Debuggen vs. Testen
Debugging-Methoden und Werkzeuge
Debugger-Technologie
Debuggen nebenläufiger Programme
Zusammenfassung, Literatur
Christoph Kessler, IDA,
Linköpings universitet, 2006.
Debugging
Testen: kann Existenz eines Fehlers feststellen
(ohne Garantie auf Vollständigkeit!)
Vergleiche Ausgabe des Testkandidaten mit Referenzausgabe
(z.B. älterer, korrekter Version – Regressionstesten, z.B. DEJAGNU)
Debuggen: lokalisiere Fehler:
Iterativer Prozess
Systematisches Eingrenzen
Fehler
entdeckt Initiale
Hypothesenmenge
Ursache
Modifiziere
Hypothesenmenge
Wähle
Hypothese
Effekt
Verifiziere
Hypothese
nein
Fehler
beseitigt?
ja
C. Kessler, IDA, Linköpings universitet.
17
Feb. 2006
Debugging-Techniken und Werkzeuge (1)
Manuelle Methoden
Statisch: Code-Inspektion
Dynamisch: print-Anweisungen,
Validierung von Zusicherungen (assert() )
Werkzeuge für die manuelle Fehlersuche:
z.B.
dbx, gdb, jdb, ddd
Debug-Problem-Dokumentation
z.B.
Symbolischer Debugger
BUGZILLA (Fehler-Datenbank + Web-Interface)
Laufzeit-Schutz-Monitorsystem ibs. für Zugriffsfehler
ElectricFence,
C. Kessler, IDA, Linköpings universitet.
VALGRIND, Java VM, INSURE++, PURIFY, …
18
Feb. 2006
Debugging-Techniken und Werkzeuge (2)
Automatisches Debugging:
Formale Verifikation gegen formale Spezifikation des Programms
Oft keine oder unvollständige formale Spezifikation verfügbar
Ggf. Spezifikation herleitbar, aber dann selbst fehleranfällig
Durchsuche Quellprogramm nach sprachspezifischen Fehler-Idiomen
z.B. lint, splint, jlint
unvollständig
Fehlersuchbereich eingrenzen durch statische Analyse:
Program Slicing [Weiser’82] [Lyle, Weiser’87]
Program Dicing (Differenz zweier Slices) [Lyle, Weiser’87]
z.B. UNRAVEL slicer [Lyle’95]
Braucht gute statische Analyse (DFA, points-to-Analyse)
Konservative statische Approximation – Slices werden schnell gross
Delta-Debugging
Automatisches Eingrenzen durch Binärpartitionierung
(Eingabedaten, Code)
C. Kessler, IDA, Linköpings universitet.
19
Feb. 2006
Symbolischer Debugger (1)
Braucht Information über Namen und Typ von Speicherstellen
auf Quellcode-Niveau
d.h., die Symboltabelle und Typtabelle des Compilers
Wird bei Bedarf eingefügt (cc –g … )
Braucht Koordinaten der Programmpunkte im Quellcode (z.B. Zeilennr.)
Braucht enge Kontrollfluss-Übereinstimmung
zwischen Quellcode und Maschinencode
Unverträglich mit aggressiven Programmoptimierungen
z.B. Prefetching, Loop-invariant code hoisting,
Schleifentransformationen, Scheduling
Trade-Off Code-Effizienz Debugger-Transparenz
Kann unter gewissen Umständen dazu führen,
dass der Fehler mit Debugger nicht auftritt
(gilt auch für print-debugging)
Graphische Oberfläche (z.B. ddd, Eclipse Debug-View)
über Kommandozeilen-Debugger (z.B. dbx, gdb, jdb)
C. Kessler, IDA, Linköpings universitet.
20
Feb. 2006
Symbolischer Debugger (2)
Post-Mortem-Debugging
Nach Absturz: Lies core-file; inspiziere Speicherinhalt, Variablenwerte
Interaktives Debuggen
Berechnung anhalten
Breakpoints (Haltepunkte)
setzen, löschen
Schritt-für-Schritt-Ausführung
Ausgabe von Werten,
Ausdrucksauswertung
(Interpreter)
Variablenwerte ändern
Aufrufkeller inspizieren
Aufrufkette entlangwandern
C. Kessler, IDA, Linköpings universitet.
21
Feb. 2006
Debugger-Technik mit OS/HW-Support
Debugger-Prozess
Zu debuggender Prozess
OS
OS-IRC
fork() (via OS)
ptrace() (via OS): ”trace me”
signal() (via OS): ”stop”
wait() (via OS)
ptrace() (via OS)
Lese, schreibe Werte im Adressraum;
füge breakpoints (Spezialinstruktionen)
in Code ein …
signal() (via OS): ”resume”
signal(): ”Breakpoint”
…
Finde Breakpunkt:
trap
signal(): ”continue”
C. Kessler, IDA, Linköpings universitet.
22
Feb. 2006
Debuggen nebenläufiger Programme
Problem: Auftreten des Fehlers kann vom Schedule abhängen
Lauf 1: CPU
Thread 1
Lauf 2: CPU
Thread 2
Thread 2
Thread 1
Thread 1
Thread 2
t
Thread 2 Thread 1
Nichtdeterminismus schwer, Fehler zu reproduzieren
Lösung 1: Deterministic replay
Eingaben und Schedule aufzeichnen,
z.B. DEJAVU für Java
Lösung 2: Statische Analyse (möglicher Parallelismus, ”Data-races”)
Lösung 3: Dynamische Analyse
identifiziert shared-memory-Zugriffe zur Laufzeit
Lösung 4: Test-basierter Ansatz mit Delta-Debugging [Choi, Zeller ’02]
In Kombination mit DEJAVU
C. Kessler, IDA, Linköpings universitet.
23
Feb. 2006
Zusammenfassung und Literatur
Testen vs. Debuggen
Debugging-Methoden
Debugger-Technologie
Debuggen nebenläufiger Programme
M. Scott: Programming Language Pragmatics, Morgan Kaufmann 2000.
Abschnitt über Debugging
Srikant, Shankar: Compiler Design Handbook, CRC press 2003,
Kap. 9 über Debugger-Technologie (von Aggarwal und Kumar)
J. Rosenberg: How Debuggers Work. Wiley, 1996.
A. Zeller: Why Programs Fail. A Guide to Systematic Debugging.
Morgan Kaufmann, 2005.
A. Zeller, J. Krinke: Open-Source Programmierwerkzeuge. Dpunkt, 2003.
C. Kessler, IDA, Linköpings universitet.
24
Feb. 2006