Extended Static Checking for Java Simon Kokerbeck Universität Paderborn Proseminar Assertions Betreuer: Björn Metzler Gliederung 1. 2. 3. 4. 5. 6. Einleitung Annotation Language Performance Anwendungsfälle Vergleich Fazit Extended Static Checking for Java • Tool zum Auffinden von Laufzeitfehlern in Java Programmen • Entwickelt durch Compaq Systems Research Center • Nachfolger von ESC/Modula-3 • Entwicklung wird fortgesetzt durch KindSoftware (ESC/Java2) 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Static Checking • Prüfung findet während der Kompilierung statt • Fehler werden früh im Entwicklungsprozess gefunden • Zeitersparnis gegenüber aufwändiger Fehlersuche am Ende der Entwicklung 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Fehlerarten • null dereference errors • array bounds errors • type cast errors • race conditions • deadlocks • ... 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Einordnung von ESC/Java Fehlerabdeckung Aufwand 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Einordnung von ESC/Java Fehlerabdeckung verification ESC/Java Entscheidbarkeitsgrenze type checking Kosten 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit ESC/Java Fehlerabdeckung Laufzeit Hohe Fehlerabdeckung bei geringer Laufzeit 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit ESC/Java Fehlerabdeckung Laufzeit Aufwand Hohe Fehlerabdeckung bei geringer Laufzeit Nicht zu großer Aufwand bei Nutzung von ESC/Java 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Benutzung von ESC/Java • Ausführung in Konsole wie normaler Java Compiler • javac wird durch escjava ersetzt • Ausgabe: Warnungen, die auf potentielle Fehler hinweisen 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Annotation Language • Sämtliche Annotationen als Kommentar ➡ Kein Problem bei Nutzung des Standard Compilers • Große Ähnlichkeit zur JML Notation • Annotationen leicht verständlich • Daher gleichzeitig sinnvoller Kommentar 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Vorgehensweise 1. Code-Abschnitt programmieren 2. Mit ESC/Java kompilieren 3. Annotationen einfügen 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Vorgehensweise • Warnungen werden mit Annotationen (sog. Pragmas) behoben • Annotationen als Kommentar im Quelltext • //@ ... oder /*@ ... */ (siehe JML) Es folgt ein Beispiel 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit class Bag { int size; int[] elements; Bag(int[] input) { size = input.length; elements = new int[size]; System.arraycopy(input,0,elements,0,size); } int getMin() { int min = Integer.MAX_VALUE; for (int i = 1; i <= size; i++) { if (elements[i] < min) { min = elements[i]; } } return min; } } 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit class Bag { int size; int[] elements; Bag(int[] input) { size = input.length; Possible null dereference elements = new int[size]; System.arraycopy(input,0,elements,0,size); } int getMin() { int min = Integer.MAX_VALUE; for (int i = 1; i <= size; i++) { if (elements[i] < min) { Possible null dereference min = elements[i]; Array index possibly too large } } return min; } } 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit class Bag { int size; int[] elements; //@ requires input != null Bag(int[] input) { size = input.length; elements = new int[size]; System.arraycopy(input,0,elements,0,size); } int getMin() { int min = Integer.MAX_VALUE; for (int i = 1; i <= size; i++) { if (elements[i] < min) { Possible null dereference min = elements[i]; Array index possibly too large } } return min; } } 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit class Bag { int size; /*@ non_null*/ int[] elements; //@ requires input != null Bag(int[] input) { size = input.length; elements = new int[size]; System.arraycopy(input,0,elements,0,size); } int getMin() { int min = Integer.MAX_VALUE; for (int i = 1; i <= size; i++) { if (elements[i] < min) { Array index possibly too large min = elements[i]; } } return min; } } 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit class Bag { int size; //@ invariant 0 <= size && size <= elements.length /*@ non_null*/ int[] elements; //@ requires input != null Bag(int[] input) { size = input.length; elements = new int[size]; System.arraycopy(input,0,elements,0,size); } int getMin() { int min = Integer.MAX_VALUE; for (int i = 1; i <= size; i++) { if (elements[i] < min) { Array index possibly too large min = elements[i]; } } return min; }} 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit class Bag { int size; //@ invariant 0 <= size && size <= elements.length /*@ non_null*/ int[] elements; //@ requires input != null Bag(int[] input) { size = input.length; elements = new int[size]; System.arraycopy(input,0,elements,0,size); } int getMin() { int min = Integer.MAX_VALUE; for (int i = 0; i < size; i++) { if (elements[i] < min) { min = elements[i]; } } return min; }} 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Der Programmierer ist gefragt! • ESC/Java findet keine Fehler • Aufmerksamkeit des Programmierers wird geweckt • Annotationen sinnvoll setzen • Annotationen dienen der Einhaltung einer Spezifikation 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Performance Was bedeutet gute Performance ? • Gute Laufzeit in Praxis • Gute Fehlerabdeckung • Wenig aufwändige Kommentierung 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Theorem proving • oft sehr aufwändig • benötigt viel Rechenzeit • Probleme teilweise unentscheidbar • in der Praxis kaum sinnvoll einsetzbar 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Optimierungen in ESC/Java • Schleifen werden 1,5 Mal durchlaufen • Die Prüfung jeder einzelnen Methode ist zeitlich begrenzt • Exception Handling wird nicht berücksichtigt • Es wird nicht Methodenübergreifend geprüft 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Nachteile • Unsound ‣ Auf vorhandene Fehler könnte nicht hingewiesen werden • Incomplete ‣ Es könnte auf unmögliche Fehler hingewiesen werden 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Beispiel: Unsoundness public class Positive{ private int n = 1; //@ invariant n > 0 public void increase(){ n++; } } • Eine Warnung erfolgt nicht 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Beispiel: Incompleteness class A{ byte[] b; public void n() { b = new byte[20]; } public void m() { n(); b[0] = 2;} } • Null dereference Warning bei Zugriff auf b[0] 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Beispiel: Incompleteness class A{ byte[] b; //@ ensures b != null && b.length = 20; public void n() { b = new byte[20]; } public void m() { n(); b[0] = 2;} } • Annotation einfügen, um Problem zu beheben 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit ESC/Java Frontend • Nachkommentierung dauerte 3 Wochen • 3 neue Fehler gefunden • Im weiteren Entwicklungsverlauf wurden durch ESC/Java 6 weitere Fehler gefunden • Zeit für Tests und Fehlersuche wurde eingespart 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Allgemeine Erfahrungen • Pro 1000 Zeilen sind ca. 40-100 Annotationen notwendig • Ein Programmierer kommentiert ca. 300-600 Zeilen pro Stunde nach • Nachkommentierung sehr Zeitaufwändig • Kommentierung während der Entwicklung sehr effektiv 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit Vergleich ESC und JML ESC/Java JML Static Checking Dynamic Checking Korrektheit der Spezifikation wird bewiesen Korrektheit der Spezifikation wird getestet Erfordert eine vollständige Vollständige Spezifikation Spezifikation nicht notwendig 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5. Vergleich 6. Fazit Fazit • Automatisierte Programmverifikation • Weder Sound noch Complete • Deckt viele potenzielle Fehler auf • Gute Laufzeit • Einsatz ab Entwicklungsbeginn sehr effektiv 1. Einleitung 2. Annotation Language 3. Performance 4. Anwendungsfälle 5.Vergleich 6. Fazit