300 likes | 453 Views
Extended Static Checking for Java or Light-weight formal methods: from objects to components. Joint work with Cormac Flanagan, Mark Lillibridge, Greg Nelson, James B. Saxe, Raymie Stata Compaq SRC. K. Rustan M. Leino Microsoft Research, Redmond, WA.
E N D
Extended Static Checking for JavaorLight-weight formal methods:from objects to components Joint work with Cormac Flanagan, Mark Lillibridge, Greg Nelson, James B. Saxe, Raymie Stata Compaq SRC K. Rustan M. LeinoMicrosoft Research, Redmond, WA 6 Nov 2002FMCO 2002, Leiden, The Netherlands
Formal methods coverage programverification extended static checking decidability ceiling light-weightformal methods typechecking effort Note: Illustration not to scale
User’s view ESC/Java Warning messages Annotated Java program 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 Bag.java:45: Precondition possibly violated
Goals of ESC/Java • Practical static checking • Detect common run-time errors • null dereferences • array bounds • type casts • race conditions • deadlocks • ... • Modular checking
ESC/Java distinguishing features • Annotation language captures design decisions • Powered by automatic theorem prover • Not decidable • Not sound or complete • Performs modular checking
Method-modular checking • Check that each method satisfies its specification, assuming that all called routines satisfy theirs • Reason about implementation when it is written, not when it is used or extended
Modular checking Interface Client check Method body check Client check
Design tradeoffs • Missed errors • Spurious warnings • Annotation overhead • Performance
Tool architecture Annotated Java program Translator Verification condition Valid Automatic theorem prover Resource exhausted Counterexample context Post processor Warning messages
Tool architecture, detail Annotated Java program Sugared command Translator Primitive command Passive command Verification condition Automatic theorem prover Counterexample context Post processor Warning messages
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
Annotation language Annotated Java program • Simple • non_null • Method annotations • requires E; • modifies w; • ensures P; • exsures (T x) Q; • Object invariants • invariant E; Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages
Annotation language Annotated Java program • Specification expressions • side-effect free Java expressions • no ++, no method calls • \result, \old(E) • ensures\result == \old(x); • ==> • (\forall T x; P), (\exists T x; P) • (\forall int j; 0 <= j && j < n ==> a[j] > 0); • \typeof(E), \type(T), <: • requires\typeof(x) == \typeof(this); Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages
Annotation language Annotated Java program • Concurrency • monitored_by lock • /*@ monitored_bythis */ long x; • \lockset[lock] • requires\lockset[this]; • lock0 < lock1 • \max(\lockset) • requires \max(\lockset) < this; Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages
Annotation language Annotated Java program • Concurrency • monitored_by lock • /*@ monitored_bythis */ long x; • \lockset[lock] • requires\lockset[this]; • lock0 < lock1 • \max(\lockset) • requires \max(\lockset) < this; Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages
Annotation language Annotated Java program • Ghost variables • ghostpublic T x; • ghostpublic int objectState; • ghostpublic\TYPE elementType; • set x = E; • set objectState = Open; • set elementType = \type(T); Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages
Annotation language Annotated Java program • Ghost variables • ghostpublic T x; • ghostpublic int objectState; • ghostpublic\TYPE elementType; • set x = E; • set objectState = Open; • set elementType = \type(T); Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages
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 (\forall int x; x >> 2 >= 0); Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages
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(S, Q) = wp(S, true) wlp(S, Q) • wlp(S, Q) = wlp(S, false) Q Sugared command Primitive command Translator Passive command Verification condition Automatictheorem prover Counterexample context Post processor Warning messages
Verification condition Annotated Java program • Universal background predicate • (FORALL (t) (<: t t)) • Type-specific background predicate • (<: T_T |T_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
Verification condition generation • Easy for small languages [Dijkstra] • Much harder for real languages • Object-oriented • Typed • Dynamic allocation • Exceptions • Aliasing • Threads
Verification conditions for real programs Java x = a[ i++ ]; assume preconditions assume invariants ... ... assert postconditions assert invariants i0 = i;i = i + 1;assert (LABEL Null@218: a != null);assert (LABEL IndexNeg@218: 0 <= i0);assert (LABEL IndexTooBig@218: i0 < a.length);x = elems[a][i0]; Guarded command wlp Verification condition i0.(i0 == i ==> … )
Verification condition • Formula in untyped, first-order predicate calculus • equality and function symbols • quantifiers • arithmetic operations • select and store operations • Eg. x.y.(x > y ==> … )
Background axioms • Additional properties of Java that the theorem prover needs to know • A variable of type T always holds a value whose type is a subtype of T • The subtyping relation is reflexive, anti-symmetric, and transitive • new returns an object that is distinct from all existing objects • ... lots more ... • java.lang.Object has no supertype
Example verification condition • Verification condition large but “dumb” (IMPLIES (DISTINCT |ecReturn| |L_14.4|) (IMPLIES (AND (EQ |a@pre:2.8| |a:2.8|) (EQ |a:2.8| (asField |a:2.8| (array |T_int|))) (< (fClosedTime |a:2.8|) alloc) (EQ |n@pre:3.6| |n:3.6|) (EQ |n:3.6| (asField |n:3.6| |T_int|)) (EQ |MAX_VALUE@pre:3.4.26| |MAX_VALUE:3.4.26|) (EQ |@true| (is |MAX_VALUE:3.4.26| |T_int|)) (EQ |elems@pre| elems) (EQ elems (asElems elems)) (< (eClosedTime elems) alloc) (EQ LS (asLockSet LS)) (EQ |alloc@pre| alloc) (EQ |@true| (is |this<1>| |T_Bag|)) (EQ |@true| (isAllocated |this<1>| alloc)) (NEQ |this<1>| null)) (FORALL (tmp1 |tmp2:21.4| |tmp3:21.6| |m:12.8| |mindex:13.8| |i:14.13| |tmp0:14.28|) (AND (IMPLIES (<= 1 (select |n:3.6| |this<1>|)) (AND (LBLNEG |Null@15.10~15.10| (NEQ (select |a:2.8| |this<1>|) null)) (LBLNEG |IndexNegative@15.10~15.11| (<= 0 1)) (LBLNEG |IndexTooBig@15.10~15.11| (< 1 (arrayLength (select |a:2.8| |this<1>|)))) (IMPLIES (< (select (select elems (select |a:2.8| |this<1>|)) 1) |MAX_VALUE:3.4.26|) (AND (LBLNEG |Null@17.12~17.12| (NEQ (select |a:2.8| |this<1>|) null)) (LBLNEG |IndexNegative@17.12~17.13| (<= 0 1)) (LBLNEG |IndexTooBig@17.12~17.13| (< 1 (arrayLength (select |a:2.8| |this<1>|)))) (FORALL (|m:17.8|) (IMPLIES (EQ |m:17.8| (select (select elems (select |a:2.8| |this<1>|)) 1)) (FORALL (|i:14.28|) (IMPLIES (AND (EQ |i:14.28| (+ 1 1)) (EQ |@true| |bool$false|)) (FORALL (|tmp2:21.4<1>|) (IMPLIES (EQ |tmp2:21.4<1>| (select |a:2.8| |this<1>|)) (AND (LBLNEG |Null@21.16~21.16| (NEQ (select |a:2.8| |this<1>|) null)) (LBLNEG |IndexNegative@21.16~21.17| (<= 0 (select (store |n:3.6| |this<1>| (- (select |n:3.6| |this<1>|) 1)) |this<1>|))) (LBLNEG |IndexTooBig@21.16~21.17| (< (select (store |n:3.6| |this<1>| (- (select |n:3.6| |this<1>|) 1)) |this<1>|) (arrayLength (select |a:2.8| |this<1>|)))) (LBLNEG |Null@21.4~21.4| (NEQ |tmp2:21.4<1>| null)) (LBLNEG |IndexNegative@21.4~21.5| (<= 0 1)) (LBLNEG |IndexTooBig@21.4~21.5| (< 1 (arrayLength |tmp2:21.4<1>|))) (LBLNEG |Exception:11.6~11.6@11.2~11.2| (EQ |ecReturn| |ecReturn|))))))))))) (IMPLIES (NOT (< (select (select elems (select |a:2.8| |this<1>|)) 1) |MAX_VALUE:3.4.26|)) (FORALL (|i:14.28|) (IMPLIES (AND (EQ |i:14.28| (+ 1 1)) (EQ |@true| |bool$false|)) (FORALL (|tmp2:21.4<1>|) (IMPLIES (EQ |tmp2:21.4<1>| (select |a:2.8| |this<1>|)) (AND (LBLNEG |Null@21.16~21.16| (NEQ (select |a:2.8| |this<1>|) null)) (LBLNEG |IndexNegative@21.16~21.17| (<= 0 (select (store |n:3.6| |this<1>| (- (select |n:3.6| |this<1>|) 1)) |this<1>|))) (LBLNEG |IndexTooBig@21.16~21.17| (< (select (store |n:3.6| |this<1>| (- (select |n:3.6| |this<1>|) 1)) |this<1>|) (arrayLength (select |a:2.8| |this<1>|)))) (LBLNEG |Null@21.4~21.4| (NEQ |tmp2:21.4<1>| null)) (LBLNEG |IndexNegative@21.4~21.5| (<= 0 0)) (LBLNEG |IndexTooBig@21.4~21.5| (< 0 (arrayLength |tmp2:21.4<1>|))) (LBLNEG |Exception:11.6~11.6@11.2~11.2| (EQ |ecReturn| |ecReturn|)))))))))) (IMPLIES (NOT (<= 1 (select |n:3.6| |this<1>|))) (AND (IMPLIES (EQ |L_14.4| |L_14.4|) (FORALL (|tmp2:21.4<1>|) (IMPLIES (EQ |tmp2:21.4<1>| (select |a:2.8| |this<1>|)) (AND (LBLNEG |Null@21.16~21.16| (NEQ (select |a:2.8| |this<1>|) null)) (LBLNEG |IndexNegative@21.16~21.17| (<= 0 (select (store |n:3.6| |this<1>| (- (select |n:3.6| |this<1>|) 1)) |this<1>|))) (LBLNEG |IndexTooBig@21.16~21.17| (< (select (store |n:3.6| |this<1>| (- (select |n:3.6| |this<1>|) 1)) |this<1>|) (arrayLength (select |a:2.8| |this<1>|)))) (LBLNEG |Null@21.4~21.4| (NEQ |tmp2:21.4<1>| null)) (LBLNEG |IndexNegative@21.4~21.5| (<= 0 0)) (LBLNEG |IndexTooBig@21.4~21.5| (< 0 (arrayLength |tmp2:21.4<1>|))) (LBLNEG |Exception:11.6~11.6@11.2~11.2| (EQ |ecReturn| |ecReturn|)))))) (IMPLIES (NOT (EQ |L_14.4| |L_14.4|)) (AND (LBLNEG |Exception:11.6~11.6@11.2~11.2| (EQ |L_14.4| |ecReturn|))))))))))
(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 { static int 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
Theorem prover: “Simplify” Annotated Java program • Nelson-Oppen cooperating decision procedures • congruence 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
Automatic theorem proving Verification condition x.y.(x > y ==> … ) Automatic theorem prover(Simplify) Valid Counterexample Diverges
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
ESC/Java research platform • Annotation inference • Daikon [Ernst], Houdini [Flanagan & Leino] • Other checking tools • Calvin [Qadeer et al.], Stale-value concurrency checker [Burrows & Leino] • Formal verification without driving theorem prover • Simplify theorem prover • SLAM [Ball, Rajamani, et al.], oolong [Leino et al.], … • Teaching • Kansas State University [Dwyer & Hatcliff]