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 –
© Copyright 2026 Paperzz