270 likes | 452 Views
Predicate Abstraction for Software Verification. Cormac Flanagan Shaz Qadeer Compaq Systems Research Center. POPL02 The Continuing Saga of Predicate Abstraction . Extended Static Checking. Statically verify many correctness properties Type systems catch many errors
E N D
Predicate Abstraction for Software Verification Cormac Flanagan Shaz Qadeer Compaq Systems Research Center
Extended Static Checking • Statically verify many correctness properties • Type systems catch many errors • e.g. “Cannot multiply a number and a string” • Would like to catch additional errors • e.g. “Array index out of bounds at line 10” • And verify other correctness properties • assertions • object invariants • lightweight method specifications
Checking loops with ESC/Java /*@ loop_invariant i >= 0; loop_invariant 0 <= spot; loop_invariant spot <= MAXDIRENTRY; loop_invariant (\forall int j; 0 <= j && j < i && bdisk[addr].dirEntries[j].inum != DIRENTRY_UNUSED ==> bdisk[addr].dirEntries[j].name != name); loop_invariant (\forall int j; spot == MAXDIRENTRY && 0 <= j && j < i ==> bdisk[addr].dirEntries[j].inum != DIRENTRY_UNUSED); loop_invariant spot == MAXDIRENTRY || bdisk[addr].dirEntries[spot].inum == DIRENTRY_UNUSED; loop_invariant (\forall DirEntry t; t != de ==> t.name == \old(t.name)); loop_invariant (\forall DirEntry t; t != de ==> t.inum == \old(t.inum)); loop_invariant (\forall DirEntry t; t.inum == FS.DIRENTRY_UNUSED || (0 <= t.inum && t.inum < FS.IMAX)); */ for (i = 0; i < cwd.inode.length; i++) { GetDirEntry(de, addr, i); if (de.inum != DIRENTRY_UNUSED && de.name == name) { return ERROR; } if (de.inum == DIRENTRY_UNUSED && spot == MAXDIRENTRY) { spot = i; } }
Loop invariants C; while e do B end Set of reachable states at loop head is a loop invariant! C p sp(C, p)
I0 I1 I2 In ... ... Abstract interpretation Cousot-Cousot 77 Ik = (Jk) (Ik) = Jk Predicate abstraction Graf-Saidi 97 Abstract states J0 J1 J2 Jn ... ... Concrete states
Computing loop invariants C; while e do X; Y; end { I0 = (sp(C, true)) } { J0 = ((I0) e) } { K0 = (sp(X, (J0))) } { L0 = (sp(Y, (K0))) }
{ J1 = ((I1) e) } { K1 = (sp(X, (J1))) } { L1 = (sp(Y, (K1))) } Computing loop invariants C; while e do X; Y; end { I1 = I0 L0 }
Predicate abstraction example /*@ requires a!=null && b!=null && a.length==b.length ensures \result==a.length || b[\result] */ int find(int[] a, boolean[] b) { int spot = a.length; for (int i=0; i < a.length; i++) { if (spot==a.length && a[i] != 0) spot = i; b[i] = (a[i] != 0); } return spot; } Ten predicates: a != null b != null a.length == b.length spot == a.length b[spot] spot < i 0 <= i i < a.length spot = i a[i] != 0
Computing loop invariants C; while e do X; Y; end { I0 = (sp(C, true)) } { L0 = (sp(“X;Y”, (I0)e)) }
Computing loop invariants C; while e do X; Y; end { I1 = I0 L0 } { L1 = (sp(“X;Y”, (I1)e)) }
Predicate abstraction example /*@ requires a!=null && b!=null && a.length==b.length ensures \result==a.length || b[\result] */ int find(int[] a, boolean[] b) { int spot = a.length; for (int i=0; i < a.length; i++) { if (spot==a.length && a[i] != 0) spot = i; b[i] = (a[i] != 0); } return spot; } Seven predicates: a != null b != null a.length == b.length spot == a.length b[spot] spot < i 0 <= i i < a.length spot = i a[i] != 0
H = havoc variables modified in X;Y P0 = “C;H;assume (I0)e;X;Y” Computing loop invariants C; while e do X; Y; end { I0 = (sp(C, true)) } { L0 = (sp(P0, true)) }
Computing loop invariants H = havoc variables modified in X;Y C; while e do X; Y; end { I1 = I0 L0 } P1 = “C;H;assume (I1)e;X;Y” { L1 = (sp(P1, true)) }
Predicate abstraction example /*@ requires a!=null && b!=null && a.length==b.length ensures \result==a.length || b[\result] */ int find(int[] a, boolean[] b) { int spot = a.length; for (int i=0; i < a.length; i++) { if (spot==a.length && a[i] != 0) spot = i; b[i] = (a[i] != 0); } return spot; } Four predicates: a != null b != null a.length == b.length spot == a.length b[spot] spot < i 0 <= i i < a.length spot = i a[i] != 0
Predicate abstraction example /*@ requires a!=null && b!=null && a.length==b.length ensures ( int j; 0<=j && j<\result ==> !b[j]) */ int find(int[] a, boolean[] b) { int spot = a.length; for (int i=0; i < a.length; i++) { if (spot==a.length && a[i] != 0) spot = i; b[i] = (a[i] != 0); } return spot; }
Invariant needed: ( int j; 0<=j && j<i && j<spot ==>!b[j]) First method: add predicate ( int j; 0<=j && j<i && j<spot ==> !b[j]) Better method: add skolem constant int j add predicates 0<=j, j<i, j<spot, !b[j] infer 0<=j && j<i && j<spot ==>!b[j] Magic: int j; 0<=j && j<i && j<spot ==>!b[j]) -quantified loop invariants
skolem_constant int sc Second set of predicates: 0 <= sc, sc < i, a[sc] != null Heuristics for guessing predicates for (int i = 0; i < a.length; i++) a[i] = null; Loop targets: i, a[*] First set of predicates: i <= \old(i), i >= \old(i) Inferred invariant: i >= 0 int sc; 0 <= sc sc < i a[sc] == null
Javafe • front end to ESC/Java • annotated with lightweight specifications • 45KLOC, 2418 routines, 520 loops • no inference warnings in 326 routines • with inference warnings in 31 routines • several failing routines had array bound violations • not caught with loop unrolling
Computing abstraction function C; {I?}while e do B end • Compute • I0=(sp(C, true)) • In+1 =In(sp(“C;H;assume (In)e;B”, true)) • Problem: Given F compute (F) • (F) = least boolean function G such that F (G)
cd cd cd cd State Space ab (F) ab F ab ab Abstract state space • Predicates {a, b, c, d} • They generate an abstract space of size 24 = 16
X X X X X X X X Naïve method (slow!) • Is F a b c dsatisfiable? No! • Can compute (F) by asking 2n such queries cd cd cd cd ab X X X (F) ab F ab ab
(F) New method • F a c d? No! • F c d? No! • F a b c d? No! • Removed 1/4 of state space in 3 queries! cd cd cd cd ab X X X X = (c d) (a c) (a b) ( c d) ab X X X F ab X X ab X X
Other methods • Das-Dill-Park 99 (DDP) • Saidi-Shankar 99 (SS)
Related work • Inferring/computing loop invariants • German-Wegbreit 75 • Katz-Manna 76 • Suzuki-Ishihata 77 • Predicate abstraction • Graf-Saidi 97 • Bensalem-Lakhnech-Owre 98, Colon-Uribe 98 • Saidi-Shankar 99, Das-Dill-Park 99 • Ball-Majumdar-Millstein-Rajamani 2001 • Henzinger-Jhala-Majumdar-Sutre 2002