Static Analysis of
Heap-manipulating Low-level software
Sumit Gulwani
MSR, Redmond
Ashish Tiwari
SRI International
Related Work
• Alias/Pointer Analysis [Work done in early 90s]
– Must/May equalities
– Considered not expressive enough
• Shape Analysis [Work that followed]
– Fancy predicates
– Need to provide transfer functions for each of them
• This work
– Must/May equalities extended with quantifiers
(Provides expressiveness of an infinite class of
predicates and avoids the need of providing transfer
functions)
1
Example 1
struct List { int Len, *Data; List* Next; }
ListOfPtrArray(struct List* x) {
for (y := x; ynull; y := y!next)
t := ?; y!len := t; y!data = malloc(4t);
for (y := x; ynull; y := y!next)
for (z :=0; z < y!len; z := z+1)
y!data!(4z) := ….;
Invariant required after first loop for proving memory safety
9i: List(x,i,next) Æ 8j: (0·j<i) )
Array(x!nextj!data, 4*(x!nextj!len))
2
Example 2
struct List { int Data; List* Next; } Prog.
Point
List2Array(struct List* x) {
1
1 n := 0;
2
for (y := x; ynull; y := y!next)
2
n := n+1;
3
3 A := malloc(4n); y:= x;
4
4 for (k := 0; k < n; k++)
5
A!(4k) := y!data;
y := y!next;
5 return A;
Invariant
9 i: List(x,i,next)
9 i: List(x,i,next),
0·n<i, y=x!nextn
List(x,n,next)
List(x,n.next), Array(A,4n)
List(x,n.next), Array(A,4n)
8 j: (0·j<n) )
A!(4j) = x!nextj!data
3
Outline
• Abstract Domain
• Implies Algorithm
• Join Algorithm
• Meet Algorithm
• PostAssignment Algorithm
4
Abstract Domain
9V: Cons Æ Must Æ May
Must := true | Must Æ 8V: (Cons ) e1=e2)
May := true | May Æ 8V: (Cons ) e1 » e2)
e := y | c | e1 § e2 |ce | e1 ! e2e3 | valid | null
Cons represent constraints over the base abstract domain,
eg. Combination of linear arithmetic and uninterpreted
functions
5
Expressiveness
List(x,i,next) ´ i ¸ 0 Æ x!nexti = null Æ
8 j: (0·j<i) ) Valid(x!nextj)
Valid(e) ´ e!w=valid
Array(x,k) ´ 8 j: (0·j<k) ) Valid(x+j)
6
Abstract Interpreter
F1
F2
True
F
Join Node
F = Join(F1,F2)
F’
F
p
False
Statement s
F
F1
F2
Conditional Node
Assignment Node
F1 = Meet(F, p)
F = Post(F’,s)
F2 = Meet(F,:p)
Where s may be:
x := e
*x := e
x := malloc(e)
free(x)
7
Implies Algorithm
Implies(F1, F2) returns 1 only if F1 ) F2
KeyIdea for checking F ) e1=e2
Check if e2 2 MustAliases(e1,F)
KeyIdea for checking F ) e1 e2
Check if : (e2 2 MayAliases(e1,F))
8
MustAliases and MayAliases
F1: x = x!nextj
F2: 8i: (0·i·j) ) x!nexti = x!nexti+1!prev
MustAliases
KeyIdea: Apply k quantifier instantiations
MustAliases(x,F1) = { x!nextj, x!next2j }
MustAliases(x,F2) =
9
MustAliases and MayAliases
F1: x = x!nextj
F2: 8j: (0·i·j) ) x!nexti=x!nexti+1!prev
MustAliases
KeyIdea: Apply k quantifier instantiations
MustAliases(x,F1) = { x!nextj, x!next2j }
MustAliases(x,F2) = { x!next!prev,
x!next!prev!next!prev }
10
MustAliases and MayAliases
F1: x = x!nextj
F2: 8j: (0·i·j) ) x!nexti=x!nexti+1!prev
MustAliases
KeyIdea: Apply k instantiations of each equality
MustAliases(x,F1) = { x!nextj, x!next2j }
MustAliases(x,F2) = { x!next!prev,
x!next!prev!next!prev }
MayAliases
KeyIdea: Represent aliases by expressions of size k
MayAliases(x,F1) = { x!nextt | t¸j }
MayAliases(x,F2) =
11
MustAliases and MayAliases
F1: x = x!nextj
F2: 8j: (0·i·j) ) x!nexti=x!nexti+1!prev
MustAliases
KeyIdea: Apply k instantiations of each equality
MustAliases(x,F1) = { x!nextj, x!next2j }
MustAliases(x,F2) = { x!next!prev,
x!next!prev!next!prev }
MayAliases
KeyIdea: Represent aliases by expressions of size k
MayAliases(x,F1) = { x!nextt | t¸j }
MayAliases(x,F2) = { x!(next|prev)t | t¸0 }
12
Join Algorithm
Join(F1, F2) returns an overapproximation of F1 Ç F2
Example 1
Input 1: i=1 Æ A[0]=0
Input 2: i=2 Æ A[0]=0 Æ A[1]=1
Output: 8 j: (0·j<i) ) A[j]=j
Example 2
Let S(k) ´ Array(x!nextk!data, x!nextk!len)
Input 1: y=x!next Æ S(0)
Input 2: y=x!next2 Æ S(0) Æ S(1)
Output: 9i: 1·i·2 Æ y=x!nexti Æ 8j: (0·j<i) ) S(j)
13
Join Algorithm: Key Idea
Input 1: y=x!next Æ S(0)
Input 2: y=x!next2 Æ S(0) Æ S(1)
After Normalization, we get:
Input 1: 9i: i=1 Æ y=x!nexti Æ 8j: (0·j<1) ) S(j)
Input 2: 9i: i=2 Æ y=x!nexti Æ 8j: (0·j<2) ) S(j)
Now we use the following rule:
Join (9V: E1 Æ 8U: C1)S, 9V: E2 Æ 8U: C2)S) =
9V: E3 Æ 8U: C3)S
where E3 = Join(E1, E2)
C3 = Underapproximation of C1ÆC2
14
Join Algorithm: Key Idea
Input 1: y=x!next Æ S(0)
Input 2: y=x!next2 Æ S(0) Æ S(1)
After Normalization, we get:
Input 1: 9i: i=1 Æ y=x!nexti Æ 8j: (0·j<1) ) S(j)
Input 2: 9i: i=2 Æ y=x!nexti Æ 8j: (0·j<2) ) S(j)
Now we use the following rule:
Join (9V: E1 Æ 8U: C1)S, 9V: E2 Æ 8U: C2)S) =
9V: E3 Æ 8U: C3)S
where E3 = Join(E1, E2)
C3 = Underapproximation of (E1)C1 Æ E2)C2)
15
Meet Algorithm
Meet(F,p) returns an overapproximation of F Æ p
KeyIdea: Reason about interaction between
equalities & disequalities
Example 1
Input 1: 9 i: len·i Æ List(x,i,next) Æ y=x!nextlen
Input 2: y=null
Output: 9 i: len=i Æ List(x,i,next) Æ y=x!nextlen
Example 2
Input 1: 9 i: len·i Æ List(x,i,next) Æ y=x!nextlen
Input 2: ynull
Output: 9 i: len<i Æ List(x,i,next) Æ y=x!nextlen
16
PostAssignment Algorithm
Post(F, s) returns an overapproximation of the strongest
postcondition of F w.r.t. s
KeyIdea: Transitive Closure; Invalidate Must; Invalidate
May; Add new fact
result
null
y
tmp
Input 1: List(y,i,next) Æ List(result,j,next) Æ
y+next=x Æ *x=tmp
Input 2: *x := result
Output: List(tmp,i-1,next) Æ List(result,j,next) Æ
y+next=x Æ *x=result
null
17
Experiments
Program
Base
Constraint
Domain
Required
Property Discovered Precondition
(apart from memory provided
safety)
List2Array
Generalized
Difference
Constraints
Corresponding array Input is a list
& list elements are
same
ListReverse
Generalized
Difference
Constraints
Reversed list has
length 100
ArrayPtrArray Generalized
Difference
Constraints +
Uninterpreted
Functions
Input is a list
of size 100
Input array has
length Len
(where Len is
also an input)
18
Related Work
• Alias/Pointer Analysis [Work done in early 90s]
– Must/May equalities
– Considered not expressive enough
• Shape Analysis [Work that followed]
– Fancy predicates
– Need to provide transfer functions for each of them
• This work
– Must/May equalities extended with quantifiers
(Provides expressiveness of an infinite class of
predicates and avoids the need of providing transfer
functions)
19
Conclusion and Future Work
• Quantified abstract domain for pointer analysis
– Expressive enough to reason rich properties
– Amenable to automated deduction
• Extend analysis to inter-procedural setting
• Add disjunction and richer quantification support
in abstract domain
20
© Copyright 2026 Paperzz