1 / 44

Verifying Properties of Well-Founded Linked Lists

Verifying Properties of Well-Founded Linked Lists. Shuvendu K. Lahiri Shaz Qadeer. Software Reliability Research Microsoft Research. Motivation for analyzing linked lists. Verify control, memory, and API safety of low-level systems code Integers Arrays Singly linked lists

mari
Download Presentation

Verifying Properties of Well-Founded Linked Lists

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. Verifying Properties of Well-Founded Linked Lists Shuvendu K. Lahiri Shaz Qadeer Software Reliability Research Microsoft Research

  2. Motivation for analyzing linked lists • Verify control, memory, and API safety of low-level systems code • Integers • Arrays • Singly linked lists • Doubly linked lists (acyclic and cyclic)

  3. Motivation for analyzing linked lists • Verify control, memory, and API safety of low-level systems code • Integers • Arrays • Singly linked lists • Doubly linked lists (acyclic and cyclic) • Establish properties about linking structure and content • Absence of null dereference, memory leaks • All elements of a list have data value 0 • List1 and List2 are disjoint

  4. //@ requires hd != null //@ ensures v  R(hd): v.data = 0 void acyclic_simple(Cell hd) { Cell iter = hd; while (iter != null) { iter.data = 0; iter = iter.next; } } Example: Acyclic linked list iteration

  5. Problem • Existing program analyses either lack scalability or precision for such programs/properties

  6. Reasoning in first-order logic • Can support many theories important for program verification • Uninterpreted functions, linear arithmetic, arrays, quantifiers • Reason about programs with a mix of scalar variables, arithmetic, arrays • Powerful analysis engines • Pioneering work by Nelson-Oppen[’79] • Recent advances in SAT-based theorem provers

  7. Program verification and first-order logic • Automated software verification tools • SLAM, BLAST, MAGIC,… • ESC/JAVA, Boogie,.. • Perform symbolic reasoning for first-order logic • Theorem provers to discharge verification conditions • Operations for abstract interpretation (predicate abstraction, join, ..) • Automatic abstraction-refinement

  8. Linked lists and reach x • Class Cell { • int data; • Cell next; • }; R(x) R(u) = Set of cells reachable from u using next field = {u, u.next, u.next.next,…}

  9. Acyclic linked list iteration //@ requires hd != null //@ ensures v  R(hd): v.data = 0 void acyclic_simple(Cell hd) { Cell iter = hd; while (iter != null) { iter.data = 0; iter = iter.next; } } hd iter Visited = R(hd)\ R(iter) Example Loop invariant u Visited: u.data = 0

  10. Reachability predicate • Need to reason about reachability predicate • e.g. u R(x): u.data = 0 • Need axioms to relate the field next and R • However, reachability can’t be modeled in first-order logic • Finite first-order axiomatization of reachability impossible

  11. Motivation for this work • Simple axioms may suffice for many examples • Provide a first-order axiomatization of Reach • Necessarily incomplete • First investigated by Nelson [POPL’83] • Enable list manipulating programs (also containing integers, arrays etc.) to be analyzed uniformly • Can leverage first-order reasoning • Predicate abstraction,… • Abstraction refinement

  12. Acyclic linked list iteration //@ requires hd != null //@ ensures v  R(hd): v.data = 0 void acyclic_simple(Cell hd) { Cell iter = hd; while (iter != null) { iter.data = 0; iter = iter.next; } } hd iter Visited = R(hd)\ R(iter) Example Loop invariant u Visited: u.data = 0 Axiom for reach: u, v : v R(u)  (v = u  (u.next  null  v R(u.next)))

  13. Acyclic linked list iteration //@ requires hd != null //@ ensures v  R(hd): v.data = 0 void acyclic_simple(Cell hd) { Cell iter = hd; while (iter != null) { iter.data = 0; iter = iter.next; } } hd iter Visited = R(hd)\ R(iter) Example Loop invariant u Visited: u.data = 0 Axiom sufficient to prove the example Axiom for reach: u, v : v R(u)  (v = u  (u.next  null  v R(u.next)))

  14. Rest of the talk • How to • Handle cyclic lists • Handle destructive updates • Generate first-order axioms for Reach • Well-founded linked lists • How it makes the above tasks amenable • Results • Deciding ground fragment with Reach predicate

  15. Cyclic linked list iteration //@ requires hd points to a cyclic list //@ ensures v  R(hd): v.data = 0 void cyclic_simple(Cell hd) { hd.data = 0; iter = hd.next; while (iter != hd) { iter.data = 0; iter = iter.next; } } Part1: Cyclic List Traversal hd iter Visited = ? No way to express Visited using R alone • R for every cell in the cycle contains all the cells in the cycle

  16. Cyclic linked list iteration //@ requires hd points to a cyclic list //@ ensures v  R(hd): v.data = 0 void cyclic_simple(Cell hd) { hd.data = 0; iter = hd.next; while (iter != hd) { iter.data = 0; iter = iter.next; } } Cyclic List Traversal hd iter Visited = ? Proving even null-dereference is non-trivial

  17. Observation • Usually, every cycle of “next” has at least one distinguished cell • Usually, the “head” of the list • This cell breaks the symmetry in the list • For each linking field “f”, a subset of fields in the heap are heads • Denoted by Hf • Cells denoted by • Always includes null

  18. x y Rf(x) x Rf(z) z y New Predicates Rf and Bf • Hf = Set of head cells for field f • Rf(u) • Set of cells u, u.f, u.f.f,…, until the first cell in H • Bf(u) • The first cell from the sequence u.f, u.f.f, …, that belongs to H • The “block” for u Bf(x) = null Bf(x) = y Bf(y) = x Bf(z) = x

  19. Well-founded heap • Given Hf, a set of “head” cells for a field f • Well-founded field f • For any cell u, the sequence u.f, u.f.f, …, intersects with a cell in Hf • Well-founded heap • Every linking field f is well-founded wrt to Hf • i.e., every f cycle has at least one Hf cell

  20. Programming methodology • Programmer must supply Hf • Every mutation of the linking field f is required to preserve well-foundedness • Restricted to programs maninpulating well founded heaps only • Almost all list programs obey this restriction

  21. Cyclic linked list iteration //@ requires hd points to a cyclic list //@ ensures v  R(hd): v.data = 0 void cyclic_simple(Cell hd) { hd.data = 0; iter = hd.next; while (iter != hd) { iter.data = 0; iter = iter.next; } } Cyclic List Traversal hd iter Visited = ?

  22. Cyclic linked list iteration //@ requires hd  H  B(hd) = hd //@ ensures v  R(hd): v.data = 0 void cyclic_simple(Cell hd) { hd.data = 0; iter = hd.next; while (iter != hd) { iter.data = 0; iter = iter.next; } } Cyclic List Traversal hd R(iter) iter Visited = (iter = hd) ? R(iter) : R(hd) \ R(iter) Loop invariant: u Visited: u.data = 0 B(iter) = hd

  23. Axioms Required • Axiom for R • v  R (u)  (v = u  (u.next  H v  R(u.next)) • v  R(u)  (v = u  (u.next  null  v  R(u.next)) • Axiom for B • B(u) = u.next  H ? u.next :B(u.next) • Able to prove the example (similar to acyclic case) with these axioms

  24. Part 2: Destructive updates • x.f := y • Issues • R, B need to be updated • Since f is updated • Destructive updates may make the heap ill-founded • Flag such programs as bad

  25. Updates to R, B (some cases) • x.f := y u u x x y y R(u) = R(u) \ R(x) {x}  R(y) R(u) = R(u) \ R(x) {x} B(u) = y B(u) = B(y)

  26. Ensuring well-foundedness • x.f := y Orphan cycle: Cycle with no H cells x y Add assert ( x  R(y)  y  H ) before each x.f := y

  27. Updating cells in Hf • Hfis a program variable now • Hf.Add(x) • Adds the cell pointed to by x to Hf • Useful when creating a cycle for the first time • Hf.Remove(x) • Removes the cell pointed to by x to Hf • Remove one head when two cycles with a head each are fused • Updates to Rf, Bf still remain quantifier-free

  28. Summary: Instrumentation • Quantifier-free updates to auxiliary variables R, B • Similar to acyclic case [Dong & Su ‘95] • Very difficult to update R for cyclic lists in general • Instrumentation captures “well-foundedness” precisely • The instrumented program goes wrong (violates an assertion)iff the source program • goes wrong (violates some assertions), or • heap of the source program becomes not well-founded

  29. Part 3: Axioms Required • Base axiom for R • v  R(u)  (v = u  (u.next  H v  R(u.next)) • Base axiom for B B(u) = u.next  H ? u.next :B(u.next) • Fundamental axioms • The axioms capture the intended meaning of R and Bin any finite and well-founded state of the program

  30. Generating new axioms • Not possible to express finiteness and well-foundedness in first-order logic • Derive new axioms from the base axioms • Using induction • For well-founded heaps • We provide an induction principle to generate derived axioms from base axioms

  31. Induction principle • Proposed axiom: u. P(u) • To prove P(u) for any cell u in a finite well-founded heap • Base Case • u.f  H  P(u) • Establish for all u at a distance 1 from H cells • Induction Step • u.f  H  (P(u.f)  P(u)) • u.f has a shorter distance to H than u (well-founded induction)

  32. Some derived axioms • Transitivity • R(u,v)  R(v,w)  R(u,w) • Antisymmetry • R(u,v)  R(v,u)  u = v • Block • R(u,v)  v H  u = v • Bounded distinctness • All cells in the set {u, u.f,…,} until the first H cell are distinct from each other • Instantiate this for bounded sizes (e.g. 1) • u.f  H  u  u.f

  33. Derived Axioms • Set of axioms are fairly fundamental properties and fairly intuitive • Can be easily proved from the base axioms using the induction principle • Suffice for a large set of examples • Otherwise derive new axioms using the base axioms and induction

  34. Benefits of well-founded lists • Set of required axioms almost similar to acyclic case • Allows us to update Rf, Bf relations using simple quantifier-free formulas • Provides an induction principle to establish derived axioms easily

  35. Experimental setup Instrumentation Add R, B + Updates + Assertions VC Generator (UCLID) Annotated Source Program Theorem Prover (UCLID) Proved/Failure Axioms for R, B

  36. UCLID • Verification system for systems modeled in first-order logic • Bryant, Lahiri, Seshia, CAV’02 • Checking verification conditions • Uses quantifier instantiation • Uses various decision procedures for uninterpreted functions, arrays, arithmetic • Inferring loop invariants with indexed predicate abstraction

  37. Examples • Simple_cyclic • List traversal • Reverse • In place reversal of an acyclic list • Sorted_insert • Inserts a cell in a sorted list • Requires arithmetic reasoning • Set_union • Merges two equivalence classes implemented as cyclic lists • Dlist_remove • Removes a cell from a cyclic doubly linked list

  38. Experiments • Proving Verification Conditions (VCs) • Most examples take < 1 s • Loop Invariant synthesis using indexed predicate abstraction

  39. Synthesizing invariants by indexed predicate abstraction • Flanagan & Qadeer POPL’02 • Lahiri & Bryant VMCAI ‘04 • Principle • Provide a set of predicates P over state variables + “index variables” X • Intuitively X contains heap cells, or indices into arrays • e.g. P = {Rnext(u,v), Bnext (u) = v, a[i] < a[j] + 1, …} X = {u,v,i,j,…} • Theorem • Indexed predicate abstraction constructs the strongest loop invariant of the form X: (P) •  is a Boolean combination of predicates in P

  40. //@requires null  Hnext //@requires Bnext (l) = null //@ensures Bnext (res) = null //@ensures Rnext(res) = R0next (l) Cell reverse (Cell l){ Cell curr = l; Cell res = null; while (curr != null){ Cell tmp = curr.next; curr.next = res; res = curr; curr = tmp; } return res; } Predicates X = {u} P = { u = null, u = curr, u = res, u = l0, curr = null, l = l0, Rnext(curr,u), Rnext(res,u), Rnext(l,u), Hnext(u), R0next(l0,u), Bnext(u) = null } Tool constructs loop invariant in 0.57 sec Synthesizing invariants in UCLID

  41. Results with Predicate Abstraction • Predicates provided manually • Used Barcelogic tool for theorem proving • Note: Results significantly improved from paper

  42. Decision procedure for ground fragment • Deciding ground formulas over • Rf(u,v), ~Rf(u,v), u = f(v), u ≠ v, u  Hf, u Hf,u = Bf (v) • Reduce dependency on derived axioms • A complete framework when VCs are quantifier-free • Solving quantifier-free queries after instantiating quantifiers • Result • Checking satisfiability of a conjunction NP-complete

  43. Related work • First-order axiomatization of reachability • Nelson ’83, Lev-Ami et al. ’05 • First-order reasoning without reachability • Necula & McPeak ’05 • Shape analysis with 3-valued logic • Sagiv et al. ’99, … • TVLA • Predicate abstraction for lists • Dams et al. ’03, Balaban et al. ’05, Manevich et al. ’05, Bingham ’06 • Separation logic • O’Hearn et al. ’01, Reynolds ’02,

  44. Conclusions • Two new predicates R, B for well-founded heaps • Instrumentation of source program with auxiliary variables for the predicates • First-order axiomatization • New induction principle • Simpler derived axioms • Implementation • Leverage first-order theorem provers • Indexed predicate abstraction provides a uniform scheme for synthesizing invariants

More Related