Technologies for finding errors in object-oriented software K. Rustan M. Leino

advertisement
Technologies for finding errors
in object-oriented software
K. Rustan M. Leino
Microsoft Research, Redmond, WA
Lecture 0
Summer school on Formal Models of Software
1 Sep 2003, Tunis, Tunisia
Motivation
Software development
problem
• Software construction and
maintenance are expensive
• Reliability is costly and difficult to
achieve
Vision
• Increased programmer productivity and program
reliability through increased rigor
Record design decisions
+ Utilize automatic checking
= Detect errors and improve maintainability
User's view
Program with
specifications
Error
messages
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++;
}
Bag.java:18: Array index possibly
too large
Extended Static Checker for Java
(ESC/Java)
• Built at Compaq SRC
• Input: Java + user-supplied annotations
• Annotation language captures
programmer design decisions
• Powered by program semantics and
automatic theorem proving
• Performs modular checking
ESC/Java demo
Program checker design
tradeoffs
•
•
•
•
Missed errors
Spurious warnings
Annotation overhead
Performance
Tool architecture
Annotated Java program
Translator
Verification condition
Automatic theorem prover
Counterexample context
Post processor
Warning messages
Valid
Resource
exhausted
Tool architecture, detail
Translator
Annotated Java program
Sugared command
Primitive command
Passive command
Verification condition
Automatic theorem prover
Counterexample context
Post processor
Warning messages
Tool architecture, detail
Annotated Java
program
Annotated Java program
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Translator
Translator
Sugared
command
Sugared command
Primitive command
Passive command
Verification condition
Automatic theorem prover
Counterexample context
Post processor
Warning messages
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Annotation language
• Simple
– non_null
• Method annotations
–
–
–
–
requires E;
modifies w;
ensures E;
exsures (T x) E;
• Object invariants
– invariant E;
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Annotation language
• Simple
– non_null
• Method annotations
–
–
–
–
requires E;
modifies w;
ensures E;
exsures (T x) E;
• Object invariants
– invariant E;
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Annotation language
• Specification expressions
– side-effect free Java expressions
• no ++, no method calls
– result, old(E)
• ensures result == old(x);
– ==>
– (forall T x; E), (exists T x; E)
• (forall int j; 0 <= j && j < n ==> a[j] > 0);
– typeof(E), type(T), <:
• requires typeof(x) == typeof(this);
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Annotation language
• Specification expressions
– side-effect free Java expressions
• no ++, no method calls
– result, old(E)
• ensures result == old(x);
– ==>
– (forall T x; E), (exists T x; E)
• (forall int j; 0 <= j && j < n ==> a[j] > 0);
– typeof(E), type(T), <:
• requires typeof(x) == typeof(this);
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Annotation language
• Concurrency
– monitored_by lock
• /*@ monitored_by this */ long x;
– lockset[lock]
• requires lockset[this];
– lock0 < lock1
– max(lockset)
• requires max(lockset) < this;
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Annotation language
• Concurrency
– monitored_by lock
• /*@ monitored_by this */ long x;
– lockset[lock]
• requires lockset[this];
– lock0 < lock1
– max(lockset)
• requires max(lockset) < this;
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Annotation language
• Ghost variables
– ghost public T x;
• ghost public int objectState;
• ghost public TYPE elementType;
– set x = E;
• set objectState = Open;
• set elementType = type(T);
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Annotation language
• Ghost variables
– ghost public T x;
• ghost public int objectState;
• ghost public TYPE elementType;
– set x = E;
• set objectState = Open;
• set elementType = type(T);
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Annotation language
• 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);
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Sugared commands
• S,T
::=
|
|
|
|
|
|
|
|
|
assert E
assume E
x= E
raise
S;T
S!T
S [] T
loop {inv E} S  T end
call x = t.m(E)
…
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Sugared commands
• 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
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Sugared commands
• 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
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Primitive commands
• S,T
::=
|
|
|
|
|
|
|
|
|
assert E
assume E
x= E
raise
S;T
S!T
S [] T
loop {inv E} S  T end
call x = t.m(E)
…
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Primitive commands
• //@ requires Pre; modifies w; ensures Post;
X m(U u);
• call x = t.m(E)
var u in
u = E;
assert Pre;
var w0 in
w0 = w;
havoc w;
assume Post;
x = result
end
end
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Passive commands
• S,T
::=
|
|
|
|
|
|
assert E
assume E
x= E
raise
S;T
S!T
S [] T
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Passive commands
• if (x < 0) { x= -x; }
/*@ assert x >= 0; */
( assume x0 < 0; x1 = -x0;
x2 = x1
[] assume ¬(x0 < 0);
x2 = x0
);
assert x2 >= 0
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Passive commands
• 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
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Weakest preconditions
• 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
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
• 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}
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Weakest preconditions
•
•
•
•
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
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Verification condition
• Universal background
predicate
– (∀t ・ t <: t)
• Type-specific background
predicate
– Bag <: java.lang.Object
Counterexample
context
Post processor
Warning
messages
• Verification condition:
BPUniv && BPT ==> VCmethod
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
(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|))
Verification condition
• class T {
static int abs(int x) {
if (x < 0) { x = -x; }
//@ assert x >= 0;
}
}
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Theorem prover: “Simplify”
• 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
Annotated Java
program
Translator
Sugared
command
Primitive
command
Passive
command
Verification
condition
Automatic
theorem prover
Counterexample
context
Post processor
Warning
messages
Counterexamples and warnings
• 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.
--------------------------------------------------
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
Experience: performance
• 50% of all methods:
• 80% of all methods:
• time limit:
< 0.5 s
<1s
300 s
• total time for Javafe (~40kloc): 65 min.
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,
…
Conclusions
• Using program semantics and
automatic decision procedures for
program analysis works!
• Cost effective?
What's needed?
• Semantics of programming language
• Specification language
• Programming methodology and
disciplines
• Decision procedures
• Property inference
Download ESC/Java (tool, documentation, sources):
http://research.compaq.com/SRC/esc
http://research.compaq.com
Download