Symbolic Predicate Abstraction

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 lowlevel systems code
Integers
 Arrays
 Singly linked lists
 Doubly linked lists (acyclic and cyclic)

–2–
Motivation for analyzing linked lists
Verify control, memory, and API safety of lowlevel 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

–3–
Example: 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;
}
}
–4–
Problem
Existing program analyses either lack scalability
or precision for such programs/properties
–5–
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

–6–
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, ..)


–7–
Automatic abstraction-refinement
Linked lists and reach
Class Cell {
x
int data;
Cell next;
};
R(x)
R(u) = Set of cells reachable from u using next field
= {u, u.next, u.next.next,…}
–8–
Example
Acyclic linked list iteration
Loop invariant
u  Visited: u.data = 0
//@ requires hd != null
//@ ensures v  R(hd): v.data = 0
void acyclic_simple(Cell hd) {
hd
iter
Cell iter = hd;
while (iter != null) {
iter.data = 0;
iter = iter.next;
}
}
–9–
Visited = R(hd)\ R(iter)
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 firstorder logic

– 10 –
Finite first-order axiomatization of reachability
impossible
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,…


– 11 –
Abstraction refinement
Example
Acyclic linked list iteration
Loop invariant
u  Visited: u.data = 0
//@ requires hd != null
//@ ensures v  R(hd): v.data = 0
void acyclic_simple(Cell hd) {
hd
iter
Cell iter = hd;
while (iter != null) {
iter.data = 0;
iter = iter.next;
}
}
– 12 –
Visited = R(hd)\ R(iter)
Axiom for reach:
u, v : v  R(u)

(v = u  (u.next  null  v  R(u.next)))
Example
Acyclic linked list iteration
Loop invariant
u  Visited: u.data = 0
//@ requires hd != null
//@ ensures v  R(hd): v.data = 0
void acyclic_simple(Cell hd) {
hd
iter
Cell iter = hd;
while (iter != null) {
iter.data = 0;
iter = iter.next;
}
}
– 13 –
Visited = R(hd)\ R(iter)
Axiom for reach:
u, v : v  R(u)

(v = u  (u.next  null  v  R(u.next)))
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
– 14 –
Part1: Cyclic List Traversal
hd
Cyclic linked list iteration
//@ requires hd points to a cyclic list
iter
//@ ensures v  R(hd): v.data = 0
void cyclic_simple(Cell hd) {
hd.data = 0;
iter = hd.next;
while (iter != hd) {
Visited = ?
iter.data = 0;
iter = iter.next;
}
}
– 15 –
No way to express Visited
using R alone
 R for every cell in the cycle
contains all the cells in the cycle
Cyclic List Traversal
hd
Cyclic linked list iteration
//@ requires hd points to a cyclic list
iter
//@ ensures v  R(hd): v.data = 0
void cyclic_simple(Cell hd) {
hd.data = 0;
iter = hd.next;
while (iter != hd) {
Visited = ?
iter.data = 0;
iter = iter.next;
}
}
– 16 –
Proving even null-dereference
is non-trivial
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


– 17 –
Always includes null
New Predicates Rf and Bf

Hf = Set of head cells for
field f
x
Rf(u)

Set of cells u, u.f, u.f.f,…,
until the first cell in H
y
Rf(x)
Bf(x) = null
x
Rf(z)
Bf(u)


– 18 –
The first cell from the
sequence u.f, u.f.f, …,
that belongs to H
Bf(x) = y
Bf(y) = x
The “block” for u
Bf(z) = x
z
y
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

– 19 –
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

– 20 –
Almost all list programs obey this restriction
Cyclic List Traversal
hd
Cyclic linked list iteration
//@ requires hd points to a cyclic list
iter
//@ 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;
}
}
– 21 –
Visited = ?
Cyclic List Traversal
hd
R(iter)
Cyclic linked list iteration
//@ requires hd  H  B(hd) = hd
iter
//@ 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;
}
}
– 22 –
Visited = (iter = hd)
? R(iter)
: R(hd) \ R(iter)
Loop invariant:
u  Visited: u.data = 0
B(iter) = hd
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
– 23 –
Part 2: Destructive updates

x.f := y
Issues
– 24 –

R, B need to be updated
 Since f is updated

Destructive updates may make the heap illfounded
 Flag such programs as bad
Updates to R, B (some cases)

x.f := y
u
u
x
x
y
R (u) = R (u) \ R (x)  {x}  R (y)
B (u) = B (y)
– 25 –
y
R (u) = R (u) \ R (x)  {x}
B (u) = y
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
– 26 –
Updating cells in Hf

Hf is 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
– 27 –
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

– 28 –
The instrumented program goes wrong (violates
an assertion) iff the source program
1. goes wrong (violates some assertions), or
2. heap of the source program becomes not wellfounded
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

– 29 –
The axioms capture the intended meaning of R and B
in any finite and well-founded state of the program
Generating new axioms

Not possible to express finiteness and wellfoundedness in first-order logic
Derive new axioms from the base axioms

Using induction
For well-founded heaps

– 30 –
We provide an induction principle to generate
derived axioms from base axioms
Induction principle


Proposed axiom: u. P(u)
To prove P(u) for any cell u in a finite wellfounded heap
Base Case


u.f  H  P(u)
Establish for all u at a distance 1 from H cells
Induction Step
1.
2.
– 31 –
u.f  H  (P(u.f)  P(u))
u.f has a shorter distance to H than u (wellfounded induction)
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


– 32 –
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
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

– 33 –
Otherwise derive new axioms using the base
axioms and induction
Benefits of well-founded lists
1. Set of required axioms almost similar to
acyclic case
2. Allows us to update Rf, Bf relations using
simple quantifier-free formulas
3. Provides an induction principle to establish
derived axioms easily
– 34 –
Experimental setup
Annotated Instrumentation
Add R, B
Source
+ Updates
Program
+ Assertions
Proved/Failure
VC Generator
(UCLID)
Theorem Prover
(UCLID)
Axioms for
R, B
– 35 –
UCLID
Verification system for systems modeled in
first-order logic

Bryant, Lahiri, Seshia, CAV’02
1. Checking verification conditions


Uses quantifier instantiation
Uses various decision procedures for
uninterpreted functions, arrays, arithmetic
2. Inferring loop invariants with indexed
predicate abstraction
– 36 –
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

– 37 –
Removes a cell from a cyclic doubly linked list
Experiments
Proving Verification Conditions (VCs)

Most examples take < 1 s
Loop Invariant synthesis using indexed
predicate abstraction
– 38 –
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
– 39 –
Synthesizing invariants in UCLID
//@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
– 40 –
Results with Predicate Abstraction
 Predicates provided manually
Example
simple_cyclic
reverse
set_union
sorted_insert
dlist_remove
#-Predicates (#-index) UCLID
15
12
24
21
-
(1)
(1)
(1)
(2)
time (s)
0.12
0.57
0.66
17.32
1.23
 Used Barcelogic tool for theorem proving
Note: Results significantly improved from paper
– 41 –
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 quantifierfree

Solving quantifier-free queries after instantiating
quantifiers
Result

– 42 –
Checking satisfiability of a conjunction NPcomplete
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

– 43 –
O’Hearn et al. ’01, Reynolds ’02,
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

– 44 –