Title: Automatic Discovery of Software Contract Work in progress
1Automatic Discovery of Software ContractWork in
progress
- Yishai Feldman, Leon Gendler
2Design By Contract
- Precondition
- An obligation of the consumer (client)
- A set of assertions to be ensured before
executing a program part - Postcondition
- An obligation of the provider (server)
- A set of conditions to be fulfilled after
executing a program part - Invariant
- A set of conditions concerning the state of the
class - Ensured to hold before and after each class
operation.
3Design By Contract
- Reliability
- Avoid unexpected inputs and results
- Expresses and validates correctness arguments
- Make sure you know what your code does
- Testing
- Contract violation means a bug
- Documentation
- Express the input and outcome of each class method
4Contract
- A set of pre- and post conditions for each
operation provided by a component and an
invariant for the whole class. - Ensuring the precondition when requesting an
operation, guarantees the provider will make the
postcondition true at its end.
5Contract Example
- /
- _at_inv (top gt 0 top lt max)
- /
- class Stack private Object elems private
int top, max / _at_pre (sz gt 0) _at_post (max
sz elems ! null) / public MyStack(int sz)
max sz elems new Objectsz - / _at_pre !isFull() _at_post (top prev (top)
1) elemstop-1 obj / public void
push(Object obj) elemstop obj
- / _at_pre !isEmpty() _at_post (top prev
(top) - 1) ret elemstop / public
Object pop() return elems--top - / _at_post (ret (top max)) / public
boolean isFull() return top max - / _at_post (ret (top 0)) / public
boolean isEmpty() return top 0
6Research Purpose
- To find a proper contract for a given class by
performing static program analysis. - The contract may not be complete, there may be
pre/post conditions that will not be found - The contract will (?) be correct.
- Discover from the code itself the conditions for
its correctness (preconditions) - No intention to verify the correctness of a given
piece of code. - Describe the codes outcome and the claims about
the objects state at end of execution
(postconditions).
7Example
// _at_inv elementData ! null // _at_inv
elementCount lt elementData.length()
// _at_pre index gt 0 // _at_pre index lt
elementCount // _at_pre c ! null
- public synchronized boolean addAll(int index,
Collection c) - if (index lt 0 index gt elementCount)
- throw new ArrayIndexOutOfBoundsException(index
) - int numNew c.size()
- ensureCapacityHelper(elementCount numNew)
- int numMoved elementCount - index
- if (numMoved gt 0)
- System.arraycopy(elementData, index,
elementData, - index numNew, numMoved)
- Iterator e c.iterator()
- for (int i 0 i lt numNew i)
- elementDataindex e.next()
- elementCount numNew
- return numNew ! 0
// _at_post elementData.length() lt
pre(elementCount) c.size() // _at_post forall i,
0 lt i lt c.size() // prev(elementDataind
ex i // elementDataindex i c.size()
8Verification Condition
- A logical expression representing a program part.
- Proving the VC to be correct, proves the program
part to be correct. - Program verification
- Annotate program with assertions and loop
invariants (manually). - Build all VCs by traversing the annotated
program. - If the VC is correct then the program stands
correct according to the given assertions.
9Mechanizing Program Verification
10Hoare Triplets
- P S Q - Starting at state P and performing
S will bring us to state Q - Weakest Precondition
- wp(S, Q) The weakest initial state P in which
after performing S will bring us to state Q - WLP(S, Q) Doesnt ensure termination
- Strongest Postcondition
- SP(S, P) The strongest state Q which can be
achieved starting at P and performing S
11Weakest? Strongest?
- A is stronger than B A ? B
- A is weaker than B B ? A
- The weakest condition True
- The strongest condition False
12P S Q Weakest? Strongest?
- The stronger P means less cases to handle,
easier job for S - False S The easiest job - The customer is
always wrong, we can do whatever we want. - We need to ask S to work with the weakest P
- The least restriction on the input
- The Stronger Q means more results
- S True Second Best - We can do whatever we
want, but must terminate - We expect S to reach the strongest Q
- The maximum the operation can achieve
13Precondition Computation
- Use Weakest Precondition method to calculate
preconditions. - Start with the weakest condition True
- Traverse the code bottom-up and push the
condition through all program instructions. - Each command can add to the precondition.
14Weakest Precondition
- wp(x e, Post) Post(x e)
- Every free occurrence of x in postcondition P is
replaced by e. - wp(S1S2, Post) wp(S1, wp(S2, Post))
- Calculate the WP bottom up
- wp(if B then S1 else S2, Post) B ? wp(S1,
Post) ? ?B ? wp(S2, Post) - wp(while B do S1, Post) ?B ? Post ? B ?
wp(while B do S1, wp(S1, Post)) - L(i) ?B ? Post ? B ? wp(L(i-1))
15Automatic Discovery of Software Contracts
- Translate the source code into a structural
representation (the Plan Calculus). - Use a library of structural elements and their
contract (assertions) to assign to each
structural element its pre/post conditions. - Propagate the assertions upwards and downwards
through the plan to produce the preconditions and
the postconditions. (V.C. generation) - Add knowledge by applying heuristics of frequent
code - Simplify expressions
16Looking for a contract
- Practical
- Something the programmer can work with
- A starting point for the programmer to check for
possible bugs. - Must contain relevant data
- No local method variables
- Class members and input variables
- Must be correct, but almost also counts
- Completeness is impossible
17Implementation
- Input a Java class source code
- Translate the Java class into a plan
representation - Code written in Java using Barat
- Barat A front-end for Java to support static
analysis of Java programs. Builds a complete
abstract syntax tree from Java source code files,
enriched with name and type analysis information. - Generate a Lisp representation of a plan.
- Traverse the plan generating the contract.
- Use predefined specs assertion and known
methods library - Use ACL2 Theorem Prover to simplify generated
logical expressions and to check possible
contract assumptions.
18ACL2
- An automated reasoning system
- Developed (for the first 9 years) at
Computational Logic, Inc. and (from January,
1997) at the University of Texas at Austin. - The successor to the Nqthm (or Boyer-Moore) logic
and proof system - A Computational Logic for Applicative Common Lisp
- An automated theorem prover or proof checker
- A competent user can utilize the ACL2 system to
discover proofs of theorems stated in the ACL2
logic or to check previously discovered proofs
19WP Example
int foo (int i) int a new int5 int
j i2 ai j ...
(and (gt 5 0) (gt i 0) (lt i 5))
(and (not (eq a nil)) (gt i 0) (lt i (len a))),
(not (eq a nil)) (eq (len a) 5))
int a new int 5 (let ((j ( 2 i))) (and
(not (eq a nil)) (gt i 0) (lt i (len a)))
int j i 2 (and (not (eq a nil)) (gt i 0) (lt
i (len a)))
ai j t
20Plan Calculus
- A structural, high level representation
- Manipulation of local variables is represented as
Data Flow - Representation of Control Flow which can be
parallel. - Spec Types
- IO Spec
- Test Spec
- Join Spec
21Condition Structure
Test
Failure-wp
Success-wp
Failure
Success
Join
Outer-wp
? Test ? Failure-wp ? Test ? Success-wp
22negate-if-negative
x
int abs (int x) If (x lt 0) x -x
return x
lt
-
23Loops
- Traverse the loop several times until
- Either a fixed-point in the contract is reached
- Or a fixed number of iteration
- Usually, the first traversal contributes most of
the information. - Try to identify special behavior well-known loop
structures such as array or range iteration.
24Loop structure
25For example
for (iinit iltlimit i) ... ai x
...
lt
aset
26Vector.addAll(int, collection)
- public synchronized boolean addAll(int index,
Collection c) - if (index lt 0 index gt elementCount)
- throw new ArrayIndexOutOfBoundsException(index
) - int numNew c.size()
- ensureCapacityHelper(elementCount numNew)
- int numMoved elementCount - index
- if (numMoved gt 0)
- System.arraycopy(elementData, index,
elementData, - index numNew, numMoved)
- Iterator e c.iterator()
- int limit index numNew
- for (int i index i lt limit i)
- elementDatai e.next()
- elementCount numNew
- return numNew ! 0
27Precondition of Vector.addAll(int, collection)
- (AND (NOT (OR (lt INDEX 0) (lt ELEMENTCOUNT
INDEX))) - C
- (OR (NOT (lt 0 ( ELEMENTCOUNT (- INDEX))))
- (AND (NOT (lt ( INDEX NUMNEW) 0))
- ELEMENTDATA
- (lt ( INDEX ELEMENTCOUNT (-
INDEX)) - (LEN ELEMENTDATA))
- (lt ( INDEX NUMNEW ELEMENTCOUNT (-
INDEX)) - (LEN ELEMENTDATA))))) ...
28Precondition of Vector.addAll(int, collection)
- (AND (gt INDEX 0) (gt ELEMENTCOUNT INDEX)
- C
- (IMPLIES (lt 0 (- ELEMENTCOUNT INDEX))
- (AND (gt ( INDEX NUMNEW) 0)
- ELEMENTDATA
- (lt ELEMENTCOUNT (LEN ELEMENTDATA))
-
- (lt ( NUMNEW ELEMENTCOUNT) (LEN
ELEMENTDATA)))))
29Full Precondition
- (AND
- (NOT (OR (lt INDEX 0) (lt ELEMENTCOUNT INDEX)))
- C
- (OR (NOT (lt 0 ( ELEMENTCOUNT (- INDEX))))
- (AND (NOT (lt ( INDEX NUMNEW) 0))
- ELEMENTDATA
- (lt ( INDEX ELEMENTCOUNT (- INDEX))
- (LEN ELEMENTDATA))
- (lt ( INDEX NUMNEW ELEMENTCOUNT (-
INDEX)) - (LEN ELEMENTDATA))
- (OR (NOT (lt INDEX LIMIT))
- (AND E (lt 0 INDEX)
- (lt INDEX (LEN ELEMENTDATA))
- (OR (NOT (lt ( 1 INDEX)
LIMIT)) - (lt ( 1 INDEX) (LEN
ELEMENTDATA))))))) - (COND ((lt 0 ( ELEMENTCOUNT (- INDEX))) T)
- ((lt INDEX LIMIT)
- (AND E ELEMENTDATA (lt 0 INDEX)
- (lt INDEX (LEN ELEMENTDATA))
30Cleaning the result
- The precondition may contain irrelevant data
- internal implementation
- The precondition should contain only global and
input variables.
31Adding more knowledge
- Serial traversal
- Most commonly used loop to traverse an array (any
serial traversal) - Adding the calculation of the last loop traversal
- Add special information
- For (i init i lt limit i) ... NO BREAK
... - Assert init lt limit ? "First execution" ? ilimit
? limit-init - Assert ?(init lt limit) ? "No execution" ? i
init ? 0
32Serial Traversal
- for(i init i lt limit i)
- ai
-
- Easy to find 0 ? init lt a.len
- Better a.length() ? limit
- Method
- Add i limit (the last value of i) as a
postcondition of the loop. - Compute the loop precondition based on
- L(k) - the postcondition computed so far
- i limit - the value of i on the last iteration
33for(i0 iltn i) ai
- L(0) outer, L(i) ?p ? L(0) ? p ? wp(S,L(i-1))
- L(1) i?n ? outer ? iltn ? wp(ai, wp(i,
L(0))) - L(1) i ? n ? outer ? i lt n ? 0 ? i lt a.len
- L(2) i?n ? outer ? iltn ? wp(aii, L(1))
- L(2) i?n ? outer ? iltn ? wp(aii, i ? n ?
outer ? i lt n ? 0 ? i lt a.len) - L(2) i ? n ? outer ? i n-1 ? wp(outer) ? i lt
n ? 0 ? i lt a.len ? i1 lt n ? 0 ? i1 lt a.len - L(k) i ? n ? outer ? ? in-k ? wpk-1(outer) ?
? i lt n ? 0 ? i lt a.len) ? ik lt n ? 0 ?
ik-1 lt a.len)
34- Wp(loop, i0)
- 0 lt n ? 0 ? 0 lt a.len
- 1 lt n ? 0 ? 1 lt a.len
-
- k lt n ? 0 ? k lt a.len
- wp(aii, L(k) ? i n)) (after loop exit) ?
- wp(aii, wp(i, L(k) ? i n)) ?
- wp(ai, L(k)i i1 ? i1 n ?
- 0 ? i lt a.len ? L(k)i i1 ? i1 n ?
- 0 ? n-1 lt a.len ? L(k)i i1
35Computing Postconditions
- Similar computation as in Preconditions.
- Possible improvement
- use the already computed preconditions as an
initial value
36Class Invariant
- Finding candidates
- Assertions regarding class members
- Assertions appearing in more that one methods
preconditions. - Assertions appearing in pre and post conditions
- Checking candidate assertions
- The assertion doesnt effect contract of methods
it is not part of their contract.
37Related Research
- ESC/Java
- Statically detects common errors such as null
pointer references - Programmer adds annotations (assertion
statements) - ESC/Java issues warnings about annotations which
cannot be verified. - Translates the program into V.C.s and tries to
prove them. - Houdini
- Guesses a candidate set of annotations and uses
ESC/Java to prove them correct
38Block diagram
39ESC example
- class Bag
- int a
- int n
-
- Bag(int input)
- n input.length
- a new intn
- System.arraycopy(input, 0, a, 0, n)
-
- int extractMin()
- int m Integer.MAX_VALUE
- int mindex 0
- for (int i 0 i lt n i)
- if (ai lt m)
- mindex i
- m ai
-
-
- n--
- amindex an
- return m
-
40escjava Bag.java
41ESC example
- class Bag
- /_at_ non_null / int a
- int n
- //_at_ invariant 0 lt n n lt a.length
- //_at_ requires input ! null
- Bag(int input)
- n input.length
- a new intn
- System.arraycopy(input, 0, a, 0, n)
-
- //_at_ requires n gt 1
- int extractMin()
- int m Integer.MAX_VALUE
- int mindex 0
- for (int i 0 i lt n i)
- if (ai lt m)
- mindex i
- m ai
-
-
- n--
- amindex an
- return m
-
42Blow-up from assignment rule
- wp(x e,Q) Q(x ? e)
- Q(x ? e) may contain many copies of e
- Sequential composition of assignment statements
may yield exponentially large VC, e.g. - wp( baa cbb ... zyy, zgt0)
43References
- Bertrand Meyer, Object-Oriented Software
Construction, 2nd edition, Prentice-Hall, 1997. - Charles Rich, Richard C. Waters, The Programmer's
Apprentice, Addison-Wesley, November 1990. - Matt Kaufmann, Panagiotis Manolios, and J
Strother Moore, Computer-Aided Reasoning An
Approach, Kluwer Academic Publishers, June, 2000 - Edsger W. Dijkstra, Carel S. Scholten Predicate
Calculus and Program Semantics, Springer-Verlag,
July 1989. - Richard C. Waters, "A Method for Analyzing Loop
Programs", IEEE Transactions on Software
Engineering, vol. 5 pp. 237-247, May 1979. - Guy L. Steele Jr., Common Lisp The Language, 2nd
edition, Butterworth-Heinemann, December 1990. - David L. Detlefs, K. Rustan M. Leino, Greg
Nelson, and James B. Saxe. "Extended Static
Checking". Research Report 159, Compaq Systems
Research Center, December, 1998.