Title: Predicate Abstraction for Software Verification
1Predicate Abstraction for Software Verification
- Shaz Qadeer
- Compaq Systems Research Center
- (joint work with Cormac Flanagan)
2Systems software
- OS components
- file system, buffer cache manager
- Abstract from low-level to high-level operations
- tedious low-level programming detail
- Expected to work
- with multiple concurrent clients
- in the presence of crashes
3Outline
- Background
- verification condition
- strongest postcondition
- loop invariants
- Inferring loop invariants
- predicate abstraction
- universally-quantified invariants
- Frangipani
- Related work
4Verification condition
x a if (x lt b) x b assert x
max(a,b)
Program P
Check for validity
sp(P,true) ? x ? a ? x ? b
5Guarded command language (Dijkstra 76)
Statement S x e A B assume e A B
while I e do B end
Variables have arbitrary values in programs
initial state
if e then A else B end ? (assume e A)
(assume ?e B)
6Strongest postcondition semantics
sp(S,Q) ?y.(Qx?y ? xex?y) sp(B,sp(A,Q)) e ?
Q sp(A,Q) ? sp(B,Q)
Statement S x e A B assume e A B
Denote sp(S, true) by sp(S)
7Checking loop invariants
- Given loop
- Need to check
- Invariant holds on entry to loop
- sp( C ) ? I
- Invariant holds at end of every iteration
- sp( C H assume I ? e B) ? I
- where H havoc variables modified in B
C I while e do B end
8Desugaring loops
S while I e do B end
H havoc variables modified in B desugar(S)
assert I H assume I ( (assume
e B assert I assume false) assume ?e)
9Example
assume 0 lt a.length i 0 while (i lt
a.length) ai 0 i i
1 assert a0 0
? int j 0 lt j ? j lt i ? aj 0, 0lti
10Translation
assume 0 lt a.length i 0 assert ? int j 0
lt j ? j lt i ? aj 0 assert 0 lt i havoc
a, i assume ? int j 0 lt j ? j lt i ? aj
0 assume 0 lt i ( assume (i lt a.length)
ai 0 i i 1 assert ? int j 0 lt
j ? j lt i ? aj 0 assert 0 lt i
assume false) assume ?(i lt a.length) assert
a0 0
11ESC/Java with loop invariants
/_at_ loop_invariant i gt 0 loop_invariant 0
lt spot loop_invariant spot lt
MAXDIRENTRY loop_invariant (\forall int j
0 lt j j lt i
bdiskaddr.dirEntriesj.inum !
DIRENTRY_UNUSED gt
bdiskaddr.dirEntriesj.name !
name) loop_invariant (\forall int j spot
MAXDIRENTRY 0 lt j j lt i gt
bdiskaddr.dirEntriesj
.inum ! DIRENTRY_UNUSED)
loop_invariant spot MAXDIRENTRY
bdiskaddr.dirEntriesspot.inu
m DIRENTRY_UNUSED loop_invariant
(\forall DirEntry t t ! de gt t.name
\old(t.name)) loop_invariant (\forall
DirEntry t t ! de gt t.inum
\old(t.inum)) loop_invariant (\forall
DirEntry t t.inum FS.DIRENTRY_UNUSED
(0
lt t.inum t.inum lt FS.IMAX)) / for (i 0
i lt 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
12Outline
- Background
- verification condition
- strongest postcondition
- loop invariants
- Inferring loop invariants
- predicate abstraction
- universally-quantified invariants
- Frangipani
- Related work
13Inferring loop invariants
C I while e do B end
- Could try
- I0 sp( C )
- In1 In ? sp( C H assume In ? e B)
- In is an invariant for first n iterations
- Problem May not converge
14Divergence
State Space
I0
I1
I2
In
...
...
15Predicate abstraction
- Invariant is boolean combination of predicates
- Split problem into two parts
- Find a suitable set of predicates
- Find the boolean combination of these predicates
16Predicate abstraction (contd.)
- Predicates over program variables
- a expr1, b expr2, c expr3, d expr4
- ? boolean expression over a,b,c,d ? formula
over program variables - ? formula over program variables ? boolean
expression over a, b, c, d - ?(F) least boolean function G over a,b,c,d
such that F ? ?(G)
17Abstract state space
- Predicates a, b, c, d
- They generate an abstract space of size 24 16
?c?d
c??d
?c??d
c?d
State Space
a?b
?(F)
a??b
F
?a??b
?a?b
18Inferring loop invariants
- Compute
- I0 ?(sp( C ))
- In1 In ? ?(sp( C H assume E ? ?(In) B))
- Converges yielding valid loop invariant
- Best loop invariant for the given predicates
19Method 1 (slow!)
- Is F ? a ? b ? c ? d satisfiable? No!
- Can compute ?(F) by asking 2n such queries
?c?d
c??d
?c??d
c?d
a?b
X
X
X
X
?(F)
a??b
X
X
X
?
F
?a??b
X
X
?
?
?a?b
X
X
?
?
20Method 2 (Das-Dill-Park 99)
Order the variables a lt b lt c lt d
- O(2n1) queries
- Sensitive to ordering
21Method 3 (Shankar-Saidi 99)
Queries of size 1 F?a, F ??a, F?b, etc. Number
nC1?21
Queries of size 2 F?a?b, F??a?b, etc. Number
nC2?22
- O(3n) queries
- No ordering required
22New method
- Removed 1/4 of state space in 3 queries!
?c?d
c??d
?c??d
c?d
a?b
X
X
X
X
?(F)
? (?c ? ?d) ? (?a ? ?c) ? (?a ? ?b) ? ( c
? ?d)
a??b
X
X
X
F
?a??b
X
X
?a?b
X
X
23Universally-quantified loop invariants
/_at_ loop_invariant i gt 0 loop_invariant 0
lt spot loop_invariant spot lt
MAXDIRENTRY loop_invariant (\forall int j
0 lt j j lt i
bdiskaddr.dirEntriesj.inum !
DIRENTRY_UNUSED gt
bdiskaddr.dirEntriesj.name !
name) loop_invariant (\forall int j spot
MAXDIRENTRY 0 lt j j lt i gt
bdiskaddr.dirEntriesj
.inum ! DIRENTRY_UNUSED)
loop_invariant spot MAXDIRENTRY
bdiskaddr.dirEntriesspot.inu
m DIRENTRY_UNUSED loop_invariant
(\forall DirEntry t t ! de gt t.name
\old(t.name)) loop_invariant (\forall
DirEntry t t ! de gt t.inum
\old(t.inum)) loop_invariant (\forall
DirEntry t t.inum FS.DIRENTRY_UNUSED
(0
lt t.inum t.inum lt FS.IMAX)) / for (i 0
i lt 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
24Inferring ?-quantified loop invariants
assume 0 lt a.length i 0 /_at_ loop_invariant
0 lt i, ? int j 0 lt j ? j lt i ? aj
0 / while (i lt a.length) ai 0 i
i 1 assert a0 0
25Inferring ?-quantified loop invariants
assume 0 lt a.length i 0 /_at_ loop_predicate
0 lt i, ? int j 0 lt j ? j lt i ? aj
0 / while (i lt a.length) ai 0 i
i 1 assert a0 0
26Inferring ?-quantified loop invariants
assume 0 lt a.length i 0 /_at_
skolem_constant int j / /_at_ loop_predicate
0 lt i, 0 lt j, j lt i, aj 0 / while (i
lt a.length) ai 0 i i
1 assert a0 0
27Inferring ?-quantified loop invariants
28Inferring ?-quantified loop invariants
/_at_ loop_predicate 0 lt i, 0 lt j, j lt i, aj
0 /
I0
TFTF
TFTT
TTFF
TTFT
I1
TTTT
? 0 ? i ? ?(0 ? j) ? ?(j lt i) ? aj 0 ? 0 ? j
? j lt i
29Inferring ?-quantified loop invariants
/_at_ loop_predicate 0 lt i, 0 lt j, j lt i, aj
0 /
I0
TFTF
TFTT
TTFF
TTFT
I1
TTTT
? 0 ? i ? ? int j 0 ? j ? j lt i ? aj 0 ? ?
int j 0 ? j ? j lt i
30Outline
- Background
- verification condition
- strongest postcondition
- loop invariants
- Inferring loop invariants
- predicate abstraction
- universally-quantified invariants
- Frangipani
- Related work
31Frangipani
- Distributed file system (Thekkath, Mann, Lee
1997) - Built on top of Petal virtual disk (Lee, Thekkath
1996) - Implements the file abstraction from the virtual
disk block abstraction - Exports file and directory operations - create,
delete, rename etc. - to clients
32Verification
- Loop invariant inference built on top of ESC/Java
(Detlefs, Leino, Nelson, Saxe 1998) - ESC/Java uses automatic theorem prover Simplify
(Nelson 81) - Frangipani data structures and create modeled
abstractly in Java - Assume
- single thread of execution
- no crashes
33Data structures on disk
Inode int inum int addr int mode
int length
ibusy
F
T
T
F
F
F
idisk
addr
addr
bdisk
Block int addr Entry entries
Entry String name int inum
bbusy
T
T
F
F
F
F
Data structures in memory
- vArray contains inodes
- distinct entries must contain
- distinct inodes
vArray
vbusy
T
T
F
F
T
F
itov int ? int
34/_at_ invariant ? int i, j vbusyi ?
((vArrayi.inum j) ? (itovj i)) invariant
? int i ibusyi ? bbusyidiski.addr invarian
t idisk ? bdisk invariant ? int i idiski ?
null ? idiski.inum i . . / /_at_ requires
vbusynum ? vArraynum.mode DIR / /_at_
ensures \result ERROR ? there is an
entry with name s in directory vArraynum / int
create(int num, String s) . . .
35Main loop in create
/_at_ loop_invariant i gt 0 loop_invariant 0
lt spot loop_invariant spot lt
MAXDIRENTRY loop_invariant (\forall int j
0 lt j j lt i
bdiskaddr.dirEntriesj.inum !
DIRENTRY_UNUSED gt
bdiskaddr.dirEntriesj.name !
name) loop_invariant (\forall int j spot
MAXDIRENTRY 0 lt j j lt i gt
bdiskaddr.dirEntriesj
.inum ! DIRENTRY_UNUSED)
loop_invariant spot MAXDIRENTRY
bdiskaddr.dirEntriesspot.inu
m DIRENTRY_UNUSED loop_invariant
(\forall DirEntry t t ! de gt t.name
\old(t.name)) loop_invariant (\forall
DirEntry t t ! de gt t.inum
\old(t.inum)) loop_invariant (\forall
DirEntry t t.inum FS.DIRENTRY_UNUSED
(0
lt t.inum t.inum lt FS.IMAX)) / for (i 0
i lt 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
36Performance
37Related work
- Inferring/computing loop invariants
- Predicate abstraction
- Graf-Saidi 97
- Bensalem-Lakhnech-Owre 98, Colon-Uribe 98
- Saidi-Shankar 99, Das-Dill-Park 99
- Ball-Majumdar-Millstein-Rajamani 2001
38Future Work
- Heuristics for generating predicates
- Multiple threads
- locks, semaphores, ...
- thread-modular reasoning
- Linked lists, reachability
- Target C