Predicate Abstraction for Software Verification
This paper by Flanagan and Qadeer explores the utility of predicate abstraction in software verification, focusing on verifying procedures with specified preconditions, postconditions, and loop invariants. The authors outline a method to infer loop invariants from concrete implementations using symbolic simulation. They discuss how to generate logical formulas for procedures and prove the correctness of postconditions given a precondition. This work addresses the challenges of specifying and utilizing loop invariants, providing insights into effective software verification methods.
Predicate Abstraction for Software Verification
E N D
Presentation Transcript
Predicate Abstraction for Software Verification Cormac Flanagan Shaz Qadeer
Verifying a Procedure • Given: • Precondition • Postcondition • Loop Invariants specified for all loops • Generate a Logical Formula (F) for the procedure • And, Prove (using a decision Procedure) • Precondition && F => Postcondition
This paper… • Specifying Pre & Post conditions of procedures is a useful documentation. • Specifying Loop Invariants is tedious and difficult (and “useless”) • Infer Loop Invariants, using Predicate Abstraction
Outline of Presentation • Symbolic Simulation using Strongest Postconditions • Assuming Loop Invariants are given • Infer Loop Invariants using Predicate Abstraction
Symbolic Simulation • Convert Java to a Guarded Command Language • Starting from the Precondition, determine the Strongest Postcondition
Strongest Postconditions • Given Q a formula, S a statement • Norm(Q,S) • Given that Q is true before S • Norm(Q,S) is true after Normal Execution of S • Wrong(Q,S) • Given that Q is true before S • Wrong(Q,S) is true when S fails
Strongest Postcondition Semantics • Norm(Q, assert P) = Q && P • Wrong(Q, assert P) = Q && !P • When assert P fails we know !P is true • Norm(Q, assume P) = Q && P • Wrong(Q, assume P) = false • assume P never fails
Strongest Postcondition Semantics (2) • Norm(Q,A;B) = Norm(Norm(Q,A), B) • Norm(Q, A;B) • Norm(Q,A) is true after A • This is the Precondition for B • Wrong(Q,A;B) • Either A fails => Wrong(Q,A) is true • Or A succeeds but B fails => Wrong(Norm(Q,A), B) is true • Wrong(Q,A;B) = Wrong(Q,A) || Wrong(Norm(Q,A), B)
Strongest Postcondition Semantics (3) • Norm(Q, AB) = Norm(Q,A) || Norm(Q,B) • Wrong(Q, AB) = Wrong(Q,A) || Wrong(Q,B) • If(e) x:=y+1 else x:=y+2 • => (assume e; x:=y+1) (assume !e; x:=y+2) • Norm: e && x=y+1 || !e && x=y+2
Strongest Postcondition Semantics (4) • Assignments • Wrong(Q, x:=e) is false • As assignments can never fail • Norm(Q, x:=e) • Introduce x’ to represent old value of x • Replace all occurrences of x in Q, e with x’ • After the assignment Q is true and x=e is true • Norm: x’. x = e(x x’) && Q(x x’)
Strongest Postcondition Semantics (5) • For While loops • Requires the loop invariant, I • Replace the while loop with its Desugar. • I: (i<=n) while( i < n ) { i := i+1; } • assert I; i = y; assume I; ( (assume i<n; i:=i+1; assert I; assume false) assume !(i < n))
Strongest Postcondition Semantics (6) • Norm of the desugar: • i’.i’<=n && (i<=n) && !(i<n) • Loop Inv holds at the beginning • Loop Inv and !(Loop Condn) holds at the end • Wrong of the desugar: • !(i<=n) || i’.i’<=n && i”.i”<n && i=i”+1 && !(i<=n) • Loop Inv fails at the beginning • Loop Inv fails at the end of the loop body
i=0; n=100 T, F, T i=1; n=100 F, F, T i=2; n=100 F, T, F i=99; n=100 i=100; n=100 Predicate Abstraction Example n := 100; i := 0; while( i < n ) { i := i+1; } Predicates: i=0 i=n i<n
Predicate Abstraction • Given a Concrete System of states. • Use a Set of n Predicates Pi to map a concrete state to an abstract state • An abstract state contains n bits • Bit i represents if Pi is true/false in that state • Set of Concrete states Mapped to a Set of Abstract states ( == Boolean Function)
Using Predicate Abstraction to find the Loop Invariant • Think of the loop body as a “transition” fn. • Starting with a set of concrete states, • Symbolically execute the loop, • Combine the new states with the init states • Repeat till you reach a fixed point = Set of all “reachable” concrete states • Doing the iteration in finite Abstract domain guarantees termination • Loop Invariant = Strongest Predicate true for all reachable concrete states.
Predicate Abstraction Algorithm • - Abstraction function • - Concretization function (the inverse) • C; while e do B end; • r = ( Norm(true, C) ) • Do(Till Fixed Point of r ){ Current Concrete Set J = ( r ) Symbolically Execute: C; Havoc(targets(B)); assume e && J; B Let Q be the new Concrete Set r = r || ( Q ) }
Problems with Predicate Abstraction • Determining the set of Predicates is key • Expensive • Exponential Calls to a Decision Procedure • Each call might take (super) exponential time • Abstraction is conservative • Property P holds in AbsDomain • Concrete version of the P holds in ConcDomain • If P does not hold in AbsDomain • P may or may not hold in ConcDomain • Difficult to debug if the program has bugs.
Heuristics to Pick Predicates • For reference p, p != null • For an integer i, i is increasing/decreasing • For skolemized constant sc, 0 <= sc, sc < i, a[sc] != null • Not sure if it works for anything other than the examples.
Optimize Calls to the Decision Procedure • Query for maximal clause m, only if implied by r • Find strongest clause c, that is implied by r • A divide and conquer algorithm that “works in practice”
Results • Seemingly (??) better than previous approaches • Predicate Guessing works for 90% of 396 loops in Javafe benchmark
Conclusion • Problems with the paper • Alias Analysis? • Interprocedural Analysis? • Do not mention any domain where their approach holds