1 / 38

Extended Static Checking for Java

Extended Static Checking for Java. Cormac Flanagan. Slides courtesy of Rustan Leino. Motivation. Software development problem. Software construction and maintenance are expensive Reliability is costly and difficult to achieve. Vision.

alda
Télécharger la présentation

Extended Static Checking for Java

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Extended Static Checkingfor Java Cormac Flanagan Slides courtesy of Rustan Leino

  2. Motivation

  3. Software development problem • Software construction and maintenance are expensive • Reliability is costly and difficult to achieve

  4. Vision • Increased programmer productivity and program reliability through increased rigor Record design decisions + Utilize automatic checking= Detect more errors and reduce costs

  5. User's view Error messages Program with specifications Program checker public class Bag { private /*@non_null*/ int[] a; private int n; //@ invariant 0 <= n && n <= a.length; public Bag(/*@non_null*/ int[] initialElements) { n = initialElements.length; a = new int[n]; System.arraycopy(initialElements, 0, a, 0, n); } public void add(int x) { if (n == a.length) { int[] b = new int[2*(a.length+1)]; System.arraycopy(a, 0, b, 0, n); a = b; } a[n] = x; n++; } public int extractMin() { int m = Integer.MAX_VALUE; int mindex = 0; for (int i = 0; i < n; i++) { if (a[i] < m) { mindex = i; m = a[i]; } } if (0 < n) { n--; a[mindex] = a[n]; } return m; } // The program text continues down here, but if you’re // reading this, you probably aren’t paying attention to // the talk. Bag.java:18: Array index possibly too large

  6. Extended Static Checker for Java (ESC/Java) • Built at Systems Research Center • Input: Java + user-supplied annotations • Annotation language captures programmer design decisions • Powered by • weakest precondition semantics • automatic theorem proving • Performs modular checking

  7. Weakest Preconditions in Practice • Given procedure //@ requires Pre //@ ensures Post procedure m() { c } // c is an IMP command • Generate verification condition Pre => WP( c, Post ) • Check this VC is valid (true in all states) • If so, then any execution of m() from a Pre–state is guaranteed to terminate only in Post–states. • Use automatic theorem proving to check VC • Performs modular checking, requires annotations

  8. ESC/Java demo

  9. Program checker design tradeoffs • Missed errors • Spurious warnings • Annotation overhead • Performance

  10. ESC/Java architecture Annotated Java program Translator Verification condition Valid Automatic theorem prover Resource exhausted Counterexample context Post processor Warning messages

  11. Tool architecture, detail Annotated Java program Sugared command Translator Primitive command Passive command Verification condition Automatic theorem prover Counterexample context Post processor Warning messages

  12. Annotated Java program Annotated Java program Sugared command Sugared command Primitive command Translator Translator Primitive command Passive command Passive command Verification condition Verification condition Automatictheorem prover Automatic theorem prover Counterexample context Counterexample context Post processor Post processor Warning messages Warning messages Tool architecture, detail

  13. Annotation language Annotated Java program • Simple • non_null • Method annotations • requires E; • ensures E; • exsures (T x) E; • modifies w; • Object invariants • invariantE; Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  14. Annotation language Annotated Java program • Simple • non_null • Method annotations • requires E; • modifies w; • ensures E; • exsures (T x) E; • Object invariants • invariantE; Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  15. Annotation language Annotated Java program • Specification expressions • side-effect free Java expressions • no ++, no method calls • result • ensuresresult >= 0; • old(E) • ensuresx == old(x)+1; • (forall T x; E), (exists T x; E), ==> • (forallint j; 0 <= j && j < n ==> a[j] > 0); Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  16. Annotation language Annotated Java program • Specification expressions • side-effect free Java expressions • no ++, no method calls • result • ensuresresult >= 0; • old(E) • ensuresx == old(x)+1; • (forall T x; E), (exists T x; E), ==> • (forallint j; 0 <= j && j < n ==> a[j] > 0); Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  17. Annotation language Annotated Java program • Miscellaneous • assert E; • assume E; • assume x >= 0; // because x == y*y • nowarn • x = a[j]; //@ nowarn • axiom E; • axiom (forallint x; x ≫ 2 >= 0); • Concurrency, ghost variables Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  18. Sugared commands Annotated Java program • S,T ::= assert E | assume E | x = E | raise | S ; T | S ! T | S [] T | loop {inv E} S  T end | call x = m(E) | … Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  19. Sugared commands Annotated Java program • x = t.f.g; assert t ≠ null; tmp = select(f, t); assert tmp ≠ null; x = select(g, tmp) • if (x < 0) { x = -x; }/*@ assert x >= 0; */ ( assume x < 0; x = -x [] assume¬(x < 0) ); assert x >= 0 Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  20. Sugared commands Annotated Java program • x = t.f.g; assert lblneg(“Null@58.9”, t ≠ null); tmp = select(f, t); assert lblneg(“Null@58.11”, tmp ≠ null); x = select(g, tmp) • if (x < 0) { x = -x; }/*@ assert x >= 0; */ ( assume x < 0;assume lblpos(“Then^280:7”, true); x = -x [] assume ¬ (x < 0);assume lblpos(“Else^280:7”, true) ); assert x >= 0 Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  21. Primitive commands Annotated Java program • S,T ::= assert E | assume E | x = E | raise | S ; T | S ! T | S [] T | loop {inv E} S  T end | call x = m(E) | … Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  22. Primitive commands Annotated Java program • //@ requires Pre; modifies w; ensures Post;void m(U u); • call x = m(E) var u in u = E; assert Pre; var w0in w0 = w; havoc w; assume Post; x = result end end Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  23. | raise | S ; T | S ! T | S [] T Passive commands Annotated Java program • S,T ::= assert E | assume E | x = E Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  24. private int scanPunctuation(int nextchr) { try { boolean possibleFloatingPointNumber = (nextchr == '.'); text[0] = (char)nextchr; textlen = 1; m_in.mark(); // All paths out of the try must unmark the stream!! PunctuationPrefixTree prefix = punctuationTable; PunctuationPrefixTree lastPunctuation = prefix; int lastPunctuationLength = 0; int index = nextchr - '!'; if (index < 0 || PunctuationPrefixTree.CHILDLEN <= index) prefix = null; else prefix = prefix.children[nextchr - '!']; nextchr = m_in.read(); if (possibleFloatingPointNumber && Character.isDigit((char)nextchr)) { m_in.clearMark(); return finishFloatingPointLiteral(nextchr); } this.append(nextchr); if (prefix != null && prefix.code != TagConstants.NULL) { lastPunctuation = prefix; lastPunctuationLength = textlen - 1; m_in.mark(); } while(prefix != null) { index = nextchr - '!'; if (index < 0 || PunctuationPrefixTree.CHILDLEN <= index) prefix = null; else prefix = prefix.children[nextchr - '!']; nextchr = m_in.read(); this.append(nextchr); if (prefix != null && prefix.code != TagConstants.NULL) { lastPunctuation = prefix; lastPunctuationLength = textlen - 1; m_in.mark(); } } m_in.reset(); textlen = lastPunctuationLength; endingLoc = m_in.getLocation(); ttype = lastPunctuation.code; if (ttype != TagConstants.C_COMMENT&& ttype != TagConstants.EOL_COMMENT) nextchr = m_in.read(); return ttype; } catch (IOException e) { m_in.clearMark(); ErrorSet.fatal(m_in.getLocation(), e.toString()); return TagConstants.NULL; // Dummy } }

  25. Passive commands Annotated Java program • if (x < 0) { x= -x; }/*@ assert x >= 0; */ ( assume x0 < 0; x1 = -x0;x2 = x1 [] assume ¬(x0 < 0);x2 = x0 ); assert x2 >= 0 Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  26. Passive commands Annotated Java program • if (x < 0) { x= -x; }/*@ assert x >= 0; */ ( assume x0 < 0; assume x1 == -x0;assume x2 == x1 [] assume ¬(x0 < 0);assume x2 == x0 ); assert x2 >= 0 Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  27. Weakest preconditions Annotated Java program • A Hoare triple{P}S{Q}says that if command S is started in a state satisfying P, then S terminates without error in a state satisfying Q • The weakest precondition of a command S with respect to a postcondition Q, written wp(S,Q), is the weakest P such that{P}S{Q} Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  28. Weakest preconditions Annotated Java program • wp(assert E, Q) = E && Q • wp(assume E, Q) = E ==> Q • wp(S;T, Q) = wp(S, wp(T,Q)) • wp(S [] T, Q) = wp(S, Q) && wp(T, Q) • wp(x := E, Q) = Q[ x := E ] Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  29. private int scanPunctuation(int nextchr) { try { boolean possibleFloatingPointNumber = (nextchr == '.'); text[0] = (char)nextchr; textlen = 1; m_in.mark(); // All paths out of the try must unmark the stream!! PunctuationPrefixTree prefix = punctuationTable; PunctuationPrefixTree lastPunctuation = prefix; int lastPunctuationLength = 0; int index = nextchr - '!'; if (index < 0 || PunctuationPrefixTree.CHILDLEN <= index) prefix = null; else prefix = prefix.children[nextchr - '!']; nextchr = m_in.read(); if (possibleFloatingPointNumber && Character.isDigit((char)nextchr)) { m_in.clearMark(); return finishFloatingPointLiteral(nextchr); } this.append(nextchr); if (prefix != null && prefix.code != TagConstants.NULL) { lastPunctuation = prefix; lastPunctuationLength = textlen - 1; m_in.mark(); } while(prefix != null) { index = nextchr - '!'; if (index < 0 || PunctuationPrefixTree.CHILDLEN <= index) prefix = null; else prefix = prefix.children[nextchr - '!']; nextchr = m_in.read(); this.append(nextchr); if (prefix != null && prefix.code != TagConstants.NULL) { lastPunctuation = prefix; lastPunctuationLength = textlen - 1; m_in.mark(); } } m_in.reset(); textlen = lastPunctuationLength; endingLoc = m_in.getLocation(); ttype = lastPunctuation.code; if (ttype != TagConstants.C_COMMENT&& ttype != TagConstants.EOL_COMMENT) nextchr = m_in.read(); return ttype; } catch (IOException e) { m_in.clearMark(); ErrorSet.fatal(m_in.getLocation(), e.toString()); return TagConstants.NULL; // Dummy } }

  30. Verification condition Annotated Java program • Universal background predicate • (∀t ・ t <: t) • Type-specific background predicate • Bag <: java.lang.Object • Verification condition:BPUniv && BPT ==> VCmethod Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  31. (BG_PUSH (AND (<: T_T |T_java.lang.Object|) (EQ T_T (asChild T_T |T_java.lang.Object|)) (DISTINCT arrayType |T_boolean| |T_char| |T_byte| |T_short| |T_int| |T_long| |T_float| |T_double| |T_.TYPE| T_T |T_java.lang.Object|))) (EXPLIES (LBLNEG |vc.T.abs.2.2| (IMPLIES (AND (EQ |elems@pre| elems) (EQ elems (asElems elems)) (< (eClosedTime elems) alloc) (EQ LS (asLockSet LS)) (EQ |alloc@pre| alloc)) (NOT (AND (EQ |@true| (is |x:2.21| T_int)) (OR (AND (OR (AND (< |x:2.21| 0) (LBLPOS |trace.Then^0,3.15| (EQ |@true| |@true|)) (EQ |x:3.17| (- 0 |x:2.21|)) (EQ |x:2.21<1>| |x:3.17|)) (AND (NOT (< |x:2.21| 0)) (LBLPOS |trace.Else^1,3.4| (EQ |@true| |@true|)) (EQ |x:2.21<1>| |x:2.21|))) (NOT (LBLNEG |Assert@4.8| (>= |x:2.21<1>| 0)))) (AND (OR (AND (< |x:2.21| 0) (LBLPOS |trace.Then^0,3.15| (EQ |@true| |@true|)) (EQ |x:3.17| (- 0 |x:2.21|)) (EQ |x:2.21<1>| |x:3.17|)) (AND (NOT (< |x:2.21| 0)) (LBLPOS |trace.Else^1,3.4| (EQ |@true| |@true|)) (EQ |x:2.21<1>| |x:2.21|))) (LBLNEG |Assert@4.8| (>= |x:2.21<1>| 0)) (NOT (LBLNEG |Exception@5.2| (EQ |ecReturn| |ecReturn|))))))))) (AND (DISTINCT |ecReturn|))) Verification condition Annotated Java program • class T { staticint abs(int x) { if (x < 0) { x = -x; } //@ assert x >= 0; } } Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  32. Theorem prover: “Simplify” Annotated Java program • Nelson-Oppen cooperating decision procedures • conguence closure • linear arithmetic • partial orders • quantifiers • Key features: • automatic: no user interaction • refutation based: searches for counterexamples • heuristics tuned for program checking • labels • time limit Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  33. Counterexamples and warnings Annotated Java program • Counterexample: labels: (|IndexTooBig@26.5| |vc.Bag.add.20.2| |trace.Then^0,21.23|) context: (AND (NEQ |tmp1!a:23.23| null) (NEQ this null) (EQ |alloc@pre| alloc) (EQ |tmp4!n:26.6| 0) … (<= alloc (vAllocTime |tmp3!a:26.4|)) ) • Bag: add(int) ...-----------------------------------------------------------Bag.java:26: Warning: Array index possibly too large (IndexTooBig) a[n] = x;^Execution trace information: Executed then branch in "Bag.java", line 21, col 23.----------------------------------------------------------- Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages

  34. Experience: annotations • Capture common design decisions • Suggested immediately by warnings • Overhead: 4-10% of source code • ~1 annotation per field or parameter • Most common annotations: • non_null • container element types

  35. Experience: performance • 50% of all methods: < 0.5 s • 80% of all methods: < 1 s • time limit: 300 s • total time for Javafe (~40kloc): 65 min.

  36. Related work • ESC/Modula-3 • Full functional specification and verification • JML, LOOP, B, Penelope, ... • Languages and language features • Euclid, Eiffel, Escher, Guava, Vault, Cqual, ... • LCLint, refinement types, Types against races, ... • Other checking techniques • Abstract interpretation, PREfix, SLAM, Bandera,Java PathFinder 2, Canvas, ESP, AST Toolkit, Metal

  37. Conclusions • Using weakest precondition semantics and automatic decision procedures for program analysis works! • Cost effective?

  38. Reading • Read Hudak’s paper on functional programming. • Read at least the initial part of Pierce’s paper on foundational calculi (the part on lambda calculus).

More Related