1 / 38

Predicate Abstraction for Software Verification

Predicate Abstraction for Software Verification. Shaz Qadeer Compaq Systems Research Center (joint work with Cormac Flanagan). Systems software. OS components file system, buffer cache manager Abstract from low-level to high-level operations tedious low-level programming detail

terryreid
Download Presentation

Predicate Abstraction for Software Verification

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Predicate Abstraction for Software Verification Shaz Qadeer Compaq Systems Research Center (joint work with Cormac Flanagan)

  2. Systems 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

  3. Outline • Background • verification condition • strongest postcondition • loop invariants • Inferring loop invariants • predicate abstraction • universally-quantified invariants • Frangipani • Related work

  4. Verification condition x := a; if (x < b) { x := b; } assert x = max(a,b); Program P Check for validity: sp(P,true)  x  a  x  b

  5. Guarded 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 program’s initial state if e then A else B end  (assume e ; A)  (assumee ; B)

  6. Strongest postcondition semantics sp(S,Q) y.(Q[xy]  x=e[x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)

  7. Checking 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

  8. Desugaring 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)

  9. Example assume 0 < a.length; i := 0; while (i < a.length) { a[i] := 0; i := i + 1; } assert a[0] = 0; { int j; 0 <= j  j < i a[j] = 0, 0<=i}

  10. Translation assume 0 < a.length; i := 0; assert  int j; 0 <= j  j < i a[j] = 0; assert 0 <= i; havoc a[*], i; assume  int j; 0 <= j  j < i a[j] = 0; assume 0 <= i; ( assume (i < a.length); a[i] := 0; i := i + 1; assert  int j; 0 <= j  j < i a[j] = 0; assert 0 <= i; assume false;)  assume (i < a.length) assert a[0] = 0;

  11. ESC/Java with loop invariants /*@ 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; } }

  12. Outline • Background • verification condition • strongest postcondition • loop invariants • Inferring loop invariants • predicate abstraction • universally-quantified invariants • Frangipani • Related work

  13. Inferring loop invariants C; {I} while e do B end • Could try • I0 = sp( C ) • In+1 = In sp( C; H; assume In e; B) • In is an invariant for first n iterations • Problem: May not converge

  14. Divergence State Space I0 I1 I2 In ... ...

  15. Predicate 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

  16. Predicate 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)

  17. Abstract 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

  18. Inferring loop invariants • Compute • I0=(sp( C )) • In+1 =In(sp( C; H; assume E  (In); B)) • Converges yielding valid loop invariant • Best loop invariant for the given predicates

  19. Method 1 (slow!) • Is F  a  b  c  dsatisfiable? 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

  20. a Fa cd cd cd cd b Fab Fab ab X X X X c (F) Fabc ab X X X F ab X X ab X X Method 2 (Das-Dill-Park 99) Order the variables: a < b < c < d • O(2n+1) queries • Sensitive to ordering

  21. . . Queries of size n: . . . Number = nCn2n Method 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

  22. New method • F  a  c  d? No! • F  a  b  c  d? No! • F  c  d? No! • 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

  23. Universally-quantified loop invariants /*@ 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; } }

  24. Inferring -quantified loop invariants assume 0 < a.length; i := 0; /*@ loop_invariant 0 <= i,  int j; 0 <= j  j < i a[j] = 0 */ while (i < a.length) { a[i] := 0; i := i + 1; } assert a[0] = 0;

  25. Inferring -quantified loop invariants assume 0 < a.length; i := 0; /*@ loop_predicate 0 <= i,  int j; 0 <= j  j < i a[j] = 0 */ while (i < a.length) { a[i] := 0; i := i + 1; } assert a[0] = 0;

  26. Inferring -quantified loop invariants assume 0 < a.length; i := 0; /*@ skolem_constant int j */ /*@ loop_predicate 0 <= i, 0 <= j, j < i, a[j] = 0 */ while (i < a.length) { a[i] := 0; i := i + 1; } assert a[0] = 0;

  27. /*@ loop_predicate 0 <= i, 0 <= j, j < i, a[j] = 0 */ I0=(sp(i := 0)) In+1 =In(sp(i := 0; havoc i, a[*]; assume In i < a.length; a[i] := 0; i := i+1)) I0 TFTF TFTT TTFF TTFT I1 TTTT Inferring -quantified loop invariants

  28. Inferring -quantified loop invariants /*@ loop_predicate 0 <= i, 0 <= j, j < i, a[j] = 0 */ I0 TFTF TFTT TTFF TTFT I1 TTTT  0  i  (0  j)  (j < i)  a[j] = 0  0  j  j < i

  29. Inferring -quantified loop invariants /*@ loop_predicate 0 <= i, 0 <= j, j < i, a[j] = 0 */ I0 TFTF TFTT TTFF TTFT I1 TTTT  0  i   int j; 0  j  j < i  a[j] = 0   int j; 0  j  j < i

  30. Outline • Background • verification condition • strongest postcondition • loop invariants • Inferring loop invariants • predicate abstraction • universally-quantified invariants • Frangipani • Related work

  31. Frangipani • 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

  32. Verification • 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

  33. . . . . . . . . . . . . . . . . . . Data structures on disk: Inode { int inum; int addr; int mode; int length; } ibusy F T F T F F idisk addr addr bdisk Block { int addr; Entry[] entries; } Entry { String name; int inum; } bbusy F T F F T 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. /*@ invariant  int i, j: vbusy[i]  ((vArray[i].inum = j)  (itov[j] = i)); invariant  int i: ibusy[i]  bbusy[idisk[i].addr]; invariant idisk  bdisk; invariant  int i: idisk[i]  null  idisk[i].inum = i; . . */ /*@ requires vbusy[num]  vArray[num].mode = DIR */ /*@ ensures \result = ERROR  there is an entry with name s in directory vArray[num] */ int create(int num, String s) { . . . }

  35. Main loop in “create” /*@ 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; } }

  36. Performance

  37. Related 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

  38. Future Work • Heuristics for generating predicates • Multiple threads • locks, semaphores, ... • thread-modular reasoning • Linked lists, reachability • Target C

More Related