quantified invariant generation using an interpolating saturation prover

43
Quantified Invariant Generation using an Interpolating Saturation Prover Ken McMillan Cadence Research Labs

Upload: astra-parker

Post on 01-Jan-2016

24 views

Category:

Documents


0 download

DESCRIPTION

Quantified Invariant Generation using an Interpolating Saturation Prover. Ken McMillan Cadence Research Labs. TexPoint fonts used in EMF: A A A A A. Quantified invariants. Many systems that we would like to verify formally are effectively infinite state Parameterized protocols - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Quantified Invariant Generation using an Interpolating Saturation Prover

Quantified Invariant Generationusing an

Interpolating Saturation Prover

Ken McMillan

Cadence Research Labs

Page 2: Quantified Invariant Generation using an Interpolating Saturation Prover

Quantified invariants• Many systems that we would like to verify formally are effectively infinite

state– Parameterized protocols

– Programs manipulating unbounded data structures (arrays, heaps, stacks)

– Programs with unbounded thread creation

• To verify such systems, we must construct a quantified invariant– For all processes, array elements, threads, etc.

• Existing fully automated techniques for generating invariants are not strongly relevance driven– Invisible invariants

– Indexed predicate abstraction

– Shape analysis

Page 3: Quantified Invariant Generation using an Interpolating Saturation Prover

Interpolants and abstraction• Interpolants derived from proofs can provide an effective relevance

heuristic for constructing inductive invariants– Provides a way of generalizing proofs about bounded behaviors to the

unbounded case

• Exploits a prover’s ability to focus on relevant facts

– Used in various applications, including

• Hardware verification (propositional case)

• Predicate abstraction (quantifier-free)

• Program verification (quantifier-free)

• This talk– Moving to the first-order case, including FO(TC)

– Modifying SPASS to create an interpolating FO prover

– Apply to program verification with arrays, linked lists

Page 4: Quantified Invariant Generation using an Interpolating Saturation Prover

Invariants from unwindings• Consider this very simple approach:

– Partially unwind a program into a loop-free, in-line program

– Construct a Floyd/Hoare proof for the in-line program

– See if this proof contains an inductive invariant proving the property

• Example program:

x = y = 0;while(*) x++; y++;while(x != 0) x--; y--;assert (y == 0);

{x == y}

invariant:

Page 5: Quantified Invariant Generation using an Interpolating Saturation Prover

{x = 0 ^ y = 0}

{x = y}

{x = y}

{x = y}

{x = 0 ) y = 0}

{False}

{True}

{y = 0}

{y = 1}

{y = 2}

{y = 1}

{y = 0}

{False}

{True}

Unwind the loops

Proof of inline program contains invariants

for both loops

• Assertions may diverge as we unwind• A practical method must somehow

prevent this kind of divergence!

x = y = 0;

x++; y++;

x++; y++;

[x!=0];x--; y--;

[x!=0];x--; y--;

[x == 0][y != 0]

Page 6: Quantified Invariant Generation using an Interpolating Saturation Prover

Interpolation Lemma• If A B = false, there exists an interpolant A' for (A,B) such that:

– A implies A’– A’ is inconsistent with B– A’ is expressed over the common vocabulary of A and B

[Craig,57]

A variety of techniques exist for deriving an interpolant from a refutation of A B, generated by a theorem prover.

Page 7: Quantified Invariant Generation using an Interpolating Saturation Prover

Interpolants for sequences• Let A1...An be a sequence of formulas

• A sequence A’0...A’n is an interpolant for A1...An when

– A’0 = True

– A’i-1 ^ Ai ) A’i, for i = 1..n

– An = False

– and finally, A’i 2 L (A1...Ai) \ L(Ai+1...An)

A1 A2 A3 An...

A'1 A'2 A'3 A‘n-1...True False) ) ) )

In other words, the interpolant is a structured

refutation of A1...An

Page 8: Quantified Invariant Generation using an Interpolating Saturation Prover

Interpolants as Floyd-Hoare proofs

False

x1=y0

True

y1>x1

))

)

1. Each formula implies the next

2. Each is over common symbols of prefix and suffix

3. Begins with true, ends with false

Proving in-line programs

SSAsequence Prover

Interpolation

HoareProof

proof

x=y;

y++;

[x=y]

x1= y0

y1=y0+1

x1y1

{False}

{x=y}

{True}

{y>x}

x = y

y++

[x == y]

Page 9: Quantified Invariant Generation using an Interpolating Saturation Prover

FOCI: An Interpolating Prover• Proof-generating decision procedure for quantifier-free FOL

– Equality with uninterpreted function symbols

– Theory of arrays

– Linear rational arithmetic, integer difference bounds

• SAT Modulo Theories approach– Boolean reasoning performed by SAT solver

– Exploits SAT relevance heuristics

• Quantifier-free interpolants from proofs– Linear-time construction [TACAS 04]

– From Q-F interpolants, we can derive atomic predicates for Predicate Abstraction [Henzinger, et al, POPL 04]

• Allows counterexample-based refinement

– Integrated with software verification tools

• Berkeley BLAST, Cadence IMPACT

Page 10: Quantified Invariant Generation using an Interpolating Saturation Prover

Avoiding divergence• Programs are infinite state, so convergence to a fixed point is not

guaranteed.• What would prevent us from computing an infinite sequence of

interpolants, say, x=0, x=1, x=2,... as we unwind the loops further?• Limited completeness result [TACAS06]

– Stratify the logical language L into a hierarchy of finite languages

– Compute minimal interpolants in this hierarchy

– If an inductive invariant proving the property exists in L, you must eventually converge to one

Interpolation provides a means of static analysis in abstract domainsof infinite height. Though we cannot compute a least fixed point, wecan compute a fixed point implying a given property if one exists.

Page 11: Quantified Invariant Generation using an Interpolating Saturation Prover

Expressiveness hierarchy

CanonicalCanonicalHeapHeap

AbstractionsAbstractions

IndexedIndexedPredicatePredicate

AbstractionAbstraction

PredicatePredicateAbstractionAbstraction

88FO(TC)FO(TC)

QFQF

ParameterizedParameterizedAbstract DomainAbstract Domain

InterpolantInterpolantLanguageLanguage

Exp

ress

ive

ne

ssE

xpre

ssiv

en

ess

88FOFO

Page 12: Quantified Invariant Generation using an Interpolating Saturation Prover

Need for quantified interpolants

• Existing interpolating provers cannot produce quantified interpolants• Problem: how to prevent the number of quantifiers from diverging in the

same way that constants diverge when we unwind the loops?

for(i = 0; i < N; i++) a[i] = i;

for(j = 0; j < N; j++) assert a[j] = j;

{8 x. 0 · x ^ x < i ) a[x] = x}

invariant:

Page 13: Quantified Invariant Generation using an Interpolating Saturation Prover

Need for Reachability

• This condition needed to prove memory safety (no use after free).

• Cannot be expressed in FO– We need some predicate identifying a closed set of nodes that is allocated

• We require a theory of reachability (in effect, transitive closure)

... node *a = create_list(); while(a){ assert(alloc(a)); a = a->next; }...

invariant:

8 x (rea(next,a,x) ^ x nil ! alloc(x))

Can we build an interpolating prover for full FOLCan we build an interpolating prover for full FOLthan that handles reachability, and avoids divergence?than that handles reachability, and avoids divergence?

Page 14: Quantified Invariant Generation using an Interpolating Saturation Prover

Clausal provers• A clausal refutation prover takes a set of clauses and returns a proof of

unsatisfiability (i.e., a refutation) if possible.• A prover is based on inference rules of this form:

P1 ... Pn

C

• where P1 ... Pn are the premises and C the conclusion.

• A typical inference rule is resolution, of which this is an instance:

p(a) p(U) ! q(U)q(a)

• This was accomplished by unifying p(a) and P(U), then dropping the complementary literals.

Page 15: Quantified Invariant Generation using an Interpolating Saturation Prover

Superposition calculusModern FOL provers based on the superposition calculus

– example superposition inference:

– this is just substitution of equals for equals

– in practice this approach generates a lot of substitutions!

– use reduction order to reduce number of inferences

Q(a) P ! (a = c)

P ! Q(c)

Page 16: Quantified Invariant Generation using an Interpolating Saturation Prover

Reduction orders• A reduction order  is:

– a total, well founded order on ground terms– subterm property: f(a)  a– monotonicity: a  b implies f(a)  f(b)

• Example: Recursive Path Ordering (with Status) (RPOS)

– start with a precedence on symbols: a  b  c  f– induces a reduction ordering on ground terms:

f(f(a)  f(a)  a  f(b)  b  c  f

Page 17: Quantified Invariant Generation using an Interpolating Saturation Prover

These terms must be maximal in their clauses

Ordering Constraint• Constrains rewrites to be “downward” in the reduction order:

Q(a) P ! (a = c)

P ! Q(c)

example: this inference only possible if a  c

Thm: Superposition with OC is complete for refutation in FOL with equality.

So how do we get interpolants from these proofs?

Page 18: Quantified Invariant Generation using an Interpolating Saturation Prover

Local Proofs• A proof is local for a pair of clause sets (A,B) when every inference step

uses only symbols from A or only symbols from B.• From a local refutation of (A,B), we can derive an interpolant for (A,B) in

linear time.• This interpolant is a Boolean combination of formulas in the proof

Page 19: Quantified Invariant Generation using an Interpolating Saturation Prover

Reduction orders and locality• A reduction order is oriented for (A,B) when:

– s  t for every s L (B) and t 2L(B)

• Intuition: rewriting eliminates first A variables, then B variables.

oriented: x y c d f

x = yA B

f(x) = c

f(y) = d

c d

x = y f(x) = c ` f(y) = c

f(y) = c f(y) = d ` c = d

c = d c d ` ?

Local!!

Page 20: Quantified Invariant Generation using an Interpolating Saturation Prover

Orientation is not enough

• Local superposition gives only c=c.• Solution: replace non-local superposition with two inferences:

Q(a)

: Q(b)

A B

Q  a  b  ca = c

b = c

Q(a) a = c

Q(c)

Q(a)

a = U ! Q(U)

This “procrastination” step is an example of a reduction rule,and preserves completeness.

a = c

Q(c)

Second inference can be postponed until after resolving with : Q(b)

Page 21: Quantified Invariant Generation using an Interpolating Saturation Prover

Completeness of local inference• Thm: Local superposition with procrastination is complete for refutation

of pairs (A,B) such that:– (A,B) has a universally quantified interpolant

– The reduction order is oriented for (A,B)

• This gives us a complete method for generation of universally quantified interpolants for arbitrary first-order formulas!

• This is easily extensible to interpolants for sequences of formulas, hence we can use the method to generate Floyd/Hoare proofs for inline programs.

Page 22: Quantified Invariant Generation using an Interpolating Saturation Prover

Avoiding Divergence• As argued earlier, we still need to prevent interpolants from diverging as

we unwind the program further.• Idea: stratify the clause language

Example: Let Lk be the set of clauses with at most k

variables and nesting depth at most k.

Note that each Lk is a finite language.

• Stratified saturation prover:– Initially let k = 1

– Restrict prover to generate only clauses in Lk

– When prover saturates, increase k by one and continue

The stratified prover is complete, since every proof is contained

in some Lk.

Page 23: Quantified Invariant Generation using an Interpolating Saturation Prover

Completeness for universal invariants• Lemma: For every safety program M with a 8 safety invariant, and

every stratified saturation prover P, there exists an integer k such that P

refutes every unwinding of M in Lk, provided:

– The reduction ordering is oriented properly

• This means that as we unwind further, eventually all the interpolants are contained in Lk, for some k.

• Theorem: Under the above conditions, there is some unwinding of M for which the interpolants generated by P contain a safety invariant for M.

This means we have a complete procedure for finding universally quantified safety invariants whenever these exist!

Page 24: Quantified Invariant Generation using an Interpolating Saturation Prover

In practice• We have proved theoretical convergence. But does the procedure

converge in practice in a reasonable time?

• Modify SPASS, an efficient superposition-based saturation prover:– Generate oriented precedence orders

– Add procrastination rule to SPASS’s reduction rules

– Drop all non-local inferences

– Add stratification (SPASS already has something similar)

• Add axiomatizations of the necessary theories– An advantage of a full FOL prover is we can add axioms!

– As argued earlier, we need a theory of arrays and reachability (TC)

• Since this theory is not finitely axiomatizable, we use an incomplete axiomatization that is intended to handle typical operations in list-manipulating programs

Page 25: Quantified Invariant Generation using an Interpolating Saturation Prover

Partially Axiomatizing FO(TC)• Axioms of the theory of arrays (with select and store)

8 (A, I, V) (select(update(A,I,V), I) = V

8 (A,I,J,V) (I J ! select(update(A,I,V), J) = select(A,J))

• Axioms for reachability (rea)

8 (L,E,X) (rea(L,select(L,E),X) ! rea(L,E,X))

8 (L,E) rea(L,E,E)

[ if e->link reaches x then e reaches x]

8 (L,E,X) (rea(L,E,X) ! E = X _ rea(L,select(L,E),X))

[ if e reaches x then e = x or e->link reaches x]etc...

Since FO(TC) is incomplete, these axioms must be incomplete

Page 26: Quantified Invariant Generation using an Interpolating Saturation Prover

Simple example

for(i = 0; i < N; i++) a[i] = i;

for(j = 0; j < N; j++) assert a[j] = j;

{8 x. 0 · x ^ x < i ) a[x] = x}

invariant:

Page 27: Quantified Invariant Generation using an Interpolating Saturation Prover

i = 0;

[i < N];a[i] = i; i++;

[i < N];a[i] = i; i++;

[i >= N]; j = 0;

[j < N]; j++;

[j < N];a[j] != j;

Unwinding simple example• Unwind the loops twice

i0 = 0

i0 < Na1 = update(a0,i0,i0)i1 = i0 + 1

i1 < Na2 = update(a1,i1,i1)i2 = i+1 + 1

i ¸ N ^ j0 = 0

j0 < N ^ j1 = j0 + 1

j1 < Nselect(a2,j1) j1

invariant

invariant

{i0 = 0}

{0 · U ^ U < i1 ) select(a1,U)=U}

{0 · U ^ U < i2 ) select(a2,U)=U}

{j · U ^ U < N ) select(a2,U)=U}

{j · U ^ U < N ) select(a2,U) = U}

note: stratification prevents constants divergingas 0, succ(0), succ(succ(0)), ...

Page 28: Quantified Invariant Generation using an Interpolating Saturation Prover

List deletion example

• Invariant synthesized with 3 unwindings (after some: simplification):

a = create_list(); while(a){ tmp = a->next; free(a); a = tmp;}

{rea(next,a,nil) ^8 x (rea(next,a,x)! x = nil _ alloc(x))}

• That is, a is acyclic, and every cell is allocated• Note that interpolation can synthesize Boolean structure.

Page 29: Quantified Invariant Generation using an Interpolating Saturation Prover

More small examples

name description assertion unwindings bound time (s)array set set all array elements to 0 all elements zero 3 L 1 0.01array test set all array elements to 0 all tests O K 3 L 1 0.01

then test all elementsl l saf e create a linked list then memory safety 3 L 1 0.04

traverse itl l acyc create a linked list list acyclic 3 L 1 0.02l l del ete delete an acyclic list memory safety 2 L 1 0.01l l del mi d delete any element result acyclic 2 L 1 0.02

of acyclic listl l rev reverse an acyclic list result acyclic 3 L 1 0.02

This shows that divergence can be controlled. This shows that divergence can be controlled. But can we scale to large programs?...But can we scale to large programs?...

Page 30: Quantified Invariant Generation using an Interpolating Saturation Prover

Canonical abstraction• Abstraction replaces concrete heaps with abstract symbolic heaps• Abstraction parameterize by “instrumentation predicates”

anext next next null

Pta is_nullReaa Reaa Reaa Reaa

a

• Abstract heap represents infinite class of concrete heaps– “Summary” node represents equivalence class of concrete nodes– Dotted arcs mean “may point to”

Page 31: Quantified Invariant Generation using an Interpolating Saturation Prover

Example program

• Want to prove this program does not access a freed cell.

node *create_list(){ node *l = NULL; while(*){ node *n = malloc(...); n->next = l;

l = n; return l;}

main(){ node *a = create_list(); while(a){ assert(alloced(a)); a = a->next; }}

Page 32: Quantified Invariant Generation using an Interpolating Saturation Prover

Canonical Abstraction• Predicates: Pta, Reaa, is_null, alloc

• Relations: next

a

is_null

a

Pta is_null

a

Pta Rean is_null(n)

alloc

alloc alloc

All three abstract heaps verify property!

Rean

Rean

Rean

Pta

Rean

Rean

Page 33: Quantified Invariant Generation using an Interpolating Saturation Prover

A slightly larger program

• We have to track a, b and c to prove this property– Lets look at what happens with canonical heap abstractions...

main(){ node *a = create_list(); node *b = create_list(); node *c = create_list();

node *p = * ? a : * ? b : c

while(p){ assert(alloced(p)); p = p->next; }}

Page 34: Quantified Invariant Generation using an Interpolating Saturation Prover

After creating “a”

a

is_null(n)

a

Pta(n) is_null(n)

a

Pta(n) Ren(n) is_null(n)

alloced(n)

alloced(n) alloced(n)

• Predicates: Pta, Reaa, is_null, alloced

• Relations: next

Page 35: Quantified Invariant Generation using an Interpolating Saturation Prover

After creating “b”

a

is_null(n)

a

Pta(n) is_null(n)

alloced(n)

a

Pta(n) Ren(n) is_null(n)

alloced(n) alloced(n)

a

is_null(n)

a

Pta(n) is_null(n)

alloced(n)

a

Pta(n) Ren(n) is_null(n)

alloced(n) alloced(n)

a

is_null(n)

a

Pta(n) is_null(n)

alloced(n)

a

Pta(n) Ren(n) is_null(n)

alloced(n) alloced(n)

b

is_null(n)

b

Pta(n) is_null(n)

alloced(n)

b

Pta(n) Ren(n) is_null(n)

alloced(n) alloced(n)

b

is_null(n)

b

Pta(n) is_null(n)

alloced(n)

b

Pta(n) Ren(n) is_null(n)

alloced(n) alloced(n)

b

is_null(n)

b

Pta(n) is_null(n)

alloced(n)

b

Pta(n) Ren(n) is_null(n)

alloced(n) alloced(n)

Page 36: Quantified Invariant Generation using an Interpolating Saturation Prover

After creating “c”

[ Picture 27 abstract heaps here ]

Problem: abstraction scales exponentially with number of independentdata structures.

Page 37: Quantified Invariant Generation using an Interpolating Saturation Prover

Independent analyses• Suppose we do a Cartesian product of 3 independent analyses for a,b,c.

ais_null(n)

aPta(n)is_null(n)

aPta(n) Ren(n)is_null(n)

alloced(n)

alloced(n)alloced(n)

alloced(n)

alloced(n)

alloced(n)

bis_null(n)

bPta(n)is_null(n)

bPta(n) Ren(n)is_null(n)

alloced(n)

alloced(n)alloced(n)

alloced(n)

alloced(n)

alloced(n)

cis_null(n)

cPta(n)is_null(n)

cPta(n) Ren(n)is_null(n)

alloced(n)

alloced(n)alloced(n)

alloced(n)

alloced(n)

alloced(n)

^ ^

• How do we know we can decompose the analysis in this way and prove the property?– What if some correlations are needed between the analyses?

• For non-heap properties, one good answer is to compute interpolants.

Page 38: Quantified Invariant Generation using an Interpolating Saturation Prover

Abstraction from interpolants

• Interpolants contain inductive invariants after unrolling loops 3 times.• Interpolant after creating c:

main(){ node *a = create_list(); node *b = create_list(); node *c = create_list();

node *p = * ? x : * ? b : c

while(p){ assert(alloced(p)); p = p->next; }}

( a 0 ) alloced(a) ) ^( b 0 ) alloced(b) ) ^( c 0 ) alloced(c) )

8 x. (x 0 ^ alloced(x) ) alloced(next(x))

^

Page 39: Quantified Invariant Generation using an Interpolating Saturation Prover

Shape of the interpolant

• Invariant says that allocated cells closed under ‘next’ relation• Notice also the size of this formula is linear in the number of lists, not

exponential as is the set of shape graphs.

( a 0 ) alloced(a) ) ^( b 0 ) alloced(b) ) ^( c 0 ) alloced(c) )

8 x. (x 0 ^ alloced(x) ) alloced(next(x))

^

abc

null

alloced

next

next

Page 40: Quantified Invariant Generation using an Interpolating Saturation Prover

Suggests decomposition

• Each of these analyses proves one conjunct of the invariant.

( a 0 ) alloced(a) ) ^( b 0 ) alloced(a) ) ^( c 0 ) alloced(a) )

8 x. (x 0 ^ alloced(x) ) alloced(next(x))

^

Predicates

Canonical abstract domains

Relations

a = 0, alloced(n)

b = 0, alloced(n)

c = 0, alloced(n)

n = 0, alloced(n) next

Page 41: Quantified Invariant Generation using an Interpolating Saturation Prover

Conclusion• Interpolants and invariant generation

– Computing interpolants from proofs allows us to generalize from special cases such as loop-free unwindings

– Interpolation can extract relevant facts from proofs of these special cases

– Must avoid divergence

• Quantified invariants– Needed for programs that manipulating arrays or heaps

– FO equality prover modified to produce local proofs (hence interpolants)

• Complete for universal invariants

– Can be used to construct invariants of simple array- and list-manipulating programs, using partial axiomatization of FO(TC)

• Language stratification prevents divergence

– Might be used as a relevance heuristic for shape analysis, IPA

For this approach to work in practice, we need FO proversFor this approach to work in practice, we need FO proverswith strong relevance heuristics as in DPLL...with strong relevance heuristics as in DPLL...

Page 42: Quantified Invariant Generation using an Interpolating Saturation Prover

Expressiveness hierarchy

CanonicalCanonicalHeapHeap

AbstractionsAbstractions

IndexedIndexedPredicatePredicate

AbstractionAbstraction

PredicatePredicateAbstractionAbstraction

88FO(TC)FO(TC)

QFQF

ParameterizedParameterizedAbstract DomainAbstract Domain

InterpolantInterpolantLanguageLanguage

Exp

ress

ive

ne

ssE

xpre

ssiv

en

ess

88FOFO

Page 43: Quantified Invariant Generation using an Interpolating Saturation Prover

Need for Reachability

• This condition needed to prove memory safety (no use after free).

• Cannot be expressed in FO– We need some predicate identifying a closed set of nodes that is allocated

• We require a theory of reachability (in effect, transitive closure)

... node *a = create_list(); while(a){ assert(alloc(a)); a = a->next; }...

invariant:

8 x (rea(next,a,x) ^ x nil ! alloc(x))

Can we build an interpolating prover for full FOLCan we build an interpolating prover for full FOLthan that handles reachability, and avoids divergence?than that handles reachability, and avoids divergence?