Principles of Program Analysis
Principles of Program Analysis
net/publication/220690264
Principles of program analysis (2. corr. print).
Book · January 2005
Source: DBLP
CITATIONS READS
116 2,521
3 authors, including:
Chris Hankin
Imperial College London
198 PUBLICATIONS 5,784 CITATIONS
SEE PROFILE
All content following this page was uploaded by Chris Hankin on 09 January 2014.
The user has requested enhancement of the downloaded file.
Principles of Program Analysis
Chris Hankin
thanks to:
Flemming Nielson and Hanne Riis Nielson
Optimising compilers
Security
Some techniques:
1
[input n] ;
2
[m := 2] ;
[m := m × n]4 ;
[n := n − 1]5 ;
[output m]6 ;
2: m: unknown n: unknown
3: m: even n: unknown
4: m: even n: unknown
5: m: even n: unknown
6: m: even n: unknown
The program computes 2 times the factorial of n for any positive value of n.
Replacing statement 2 by:
2
[m := 1] ;
gives a program that computes factorials but then the program analysis is
unable to tell us anything about the parity of m at statement 6.
the program analysis will still not accurately predict the evenness of m at
statement 6.
This loss of accuracy is a common feature of program analyses: many
properties that we are interested in are essentially undecidable and
therefore we cannot hope to detect them accurately. We have to ensure
that the answers from program analysis are at least safe.
yes means definitely yes, and
no means possibly no.
Overview
Efficiency
Correctness
Introduction – two approaches to correctness
Fixed Points – widening and narrowings
Galois Connections
Induced operations
Abstract interpretation invented by Patrick Cousot and Radhia Cousot in
1977.
A first-order approach
p ` l 1 l2
R : V × L → {true, false}
The intention is that v R l formalises our claim that the value v is described
by the property l.
v1 R l 1 ∧ p ` v 1 ; v 2 ∧ p ` l 1 l 2 ⇒ v2 R l 2
v R l 1 ∧ l 1 v l2 ⇒ v R l2 (1)
v R l 1 ∧ l 1 v l2 ⇒ v R l 2
The first condition says that the smaller the property is with respect to
the partial ordering, the better (i.e. more precise) it is.
The second condition says that there is always a best property for
describing a value. This is important for having to perform only one
analysis (using the best property, i.e. the greatest lower bound of the
candidates) instead of several analyses (one for each of the
candidates).
vR>
v R l1 ∧ v R l 2 ⇒ v R (l1 u l2 )
Representation functions
β(v1 ) v l1 ∧ p ` v1 ; v2 ∧ p ` l1 l2 ⇒ β(v2 ) v l2
Thus the idea is that if the initial value v1 is safely described by l1 then the
v Rβ l iff β(v) v l
βR (v) = {l | v R l}
A modest generalisation
p ` v1 ; v2
the condition that V1 = V2 ; thus we shall allow the programs to have dif-
ferent “argument” and “result” types – for example, this will be the case for
restriction that L1 = L2 .
v1 R 1 l 1 ∧ p ` v 1 ; v 2 ⇒ v2 R2 fp (l1 )
(p ` · ; ·) (R1 →
→ R 2 ) fp
To be precise, ; (R1 →
→ R2 ) f means that:
∀v1 , v2 , l1 : v1 ; v2 ∧ v1 R1 l1 ⇒ v2 R2 f (l1 )
Higher-order formulation.
plus ` (z1 , z2 ) ; z1 + z2
where ZZ ⊆ Z × Z.
βZ (z) = {z}
βZ×Z (z1 , z2 ) = {(z1 , z2 )}
or more succinctly
(plus ` · ; ·) (RZ×Z →
→ RZ ) fplus
The representation function βZ×Z →
→ βZ satisfies
(βZ×Z →
→ βZ )(p ` · ; ·) =
λZZ.{z | (z1 , z2 ) ∈ ZZ ∧ p ` (z1 , z2 ) ; z}
fplus .
The above example illustrates how the abstract concepts can give a more
shall see several cases where we move freely between what we may call
same property. And we shall see that the latter often will allow us to reuse
general results so that we do not have to redevelop parts of the theory for
We shall now present a complete lattice that may be used for Array Bound
Analysis, i.e. for determining if an array index is always within the bounds
of the array – if this is the case then a number of run-time checks can be
eliminated.
The lattice (Interval, v) of intervals over Z may be described as follows.
The elements are
• [-∞,1] • [-1,∞]
• [-∞,0] • [-2,2] • [0,∞]
• ⊥
(
−∞ if int = ⊥
sup(int) =
z2 if int = [z1 , z2 ]
f (l1 ) = l2
Note that the demand that f is monotone is very natural for program
analysis; it merely says that if l10 describes at least the values that l1
does then also f (l10 ) describes at least the values that f (l1 ) does.
Fix(f ) = {l | f (l) = l}
Red(f ) = {l | f (l) v l}
for the set of elements upon which f is reductive; we shall say that f
itself is reductive if Red(f ) = L.
Similarly, the function f is extensive at l if and only if f (l) w l and we
write
Ext(f ) = {l | f (l) w l}
for the set of elements upon which f is extensive; we shall say that f
itself is extensive if Ext(f ) = L.
Since L is a complete lattice it is always the case that the set Fix(f ) will
have a greatest lower bound in L and we denote it by lfp(f ); this is actually
the least fixed point of f because Tarski’s Theorem ensures that:
Similarly, the set Fix(f ) will have a least upper bound in L and we denote it
by gfp(f ); this is actually the greatest fixed point of f because Tarski’s
Theorem ensures that:
G G
gfp(f ) = Fix(f ) = Ext(f ) ∈ Fix(f ) ⊆ Ext(f )
In Denotational Semantics it is customary to iterate to the least fixed point
by taking the least upper bound of the sequence (f n (⊥))n . However, we
have
F not imposed
F any continuity requirements on f (e.g. that
f ( n ln ) = n (f (ln )) for all ascending chains (ln )n ) and consequently we
cannot be sure to actually reach the fixed point. In a similar way one could
consider the greatest lower bound of the sequence (f n (>))n . One can
show that
G
n n
f (⊥) v n f (⊥) v lfp(f ) v
n
gfp(f ) v nf (>) v f n (>)
Widenings
n
The idea is now to replace it by a new sequence (f∇ )n that is known to
imation of the least fixed point. The construction of the new sequence is
l1 v (l1 ť l2 ) w l2
for all l1 , l2 ∈ L, i.e. it always returns an element larger than both its ar-
The following result expresses that any sequence can be turned into an
ascending chain by an upper bound operator:
Note that the operation is not symmetric: for int = [0, 2] we e.g. have
int int
[1, 2]ť [2, 3] = [1, 3] whereas [2, 3]ť [1, 2] = [−∞, ∞].
int
It is immediate that ť is an upper bound operator. Consider now the
sequence:
[0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], · · ·
If int = [0, ∞], then the upper bound operator will transform the above
sequence into the ascending chain:
[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], · · ·
However, if int = [0, 2], then we will get the following ascending chain
[0, 0], [0, 1], [0, 2], [0, 3], [−∞, ∞], [−∞, ∞], · · ·
[ LB(z1 , z3 ) , UB(z2 , z4 ) ]
where LB(z1 , z3 ) ∈ {z1 } ∪ K ∪ {−∞} is the best possible lower bound and
UB(z2 , z4 ) ∈ {z2 } ∪ K ∪ {∞} is the best possible upper bound. In this way
a change in any of the bounds of the interval [z1 , z2 ] can only take place in
[0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], · · ·
[0, 1], [0, 3], [0, 3], [0, 5], [0, 5], [0, ∞], [0, ∞], · · ·
Narrowings
or absorptive. One can show that (ln∆ )n is a descending chain when (ln )n
is a descending chain.
m m m m
For f∇ satisfying f (f∇ ) v f∇ , i.e. lfp∇ (f ) = f∇ , we now construct the
sequence ([f ]n∆ )n by
m
f∇ if n = 0
[f ]n∆ =
[f ]n−1 ∆ f ([f ]n−1 ) if n > 0
∆ ∆
m m
If ∆ is a narrowing operator and f (f∇ ) v f∇ then ([f ]n∆ )n is a
descending chain in Red(f ) and
[f ]n∆ w f n (f∇
m
) w lfp(f )
for all n.
m m
If ∆ is a narrowing operator and f (f∇ ) v f∇ then the descending
n
chain ([f ]∆ )n eventually stabilises.
It is important to stress that narrowing operators are not the dual
n
concept of widening operators. In particular, the sequence (f∇ )n may
step outside Ext(f ) in order to end in Red(f ), whereas the sequence
([f ]n∆ )n stays in Red(f ) all the time.
Consider the complete lattice (Interval, v). Basically there are two kinds of
infinite descending chains in Interval: those with elements of the form
[−∞, z] and those with elements of the form [z, ∞] where z ∈ Z. Consider
an infinite sequence of the latter form; it will have elements
where z1 < z2 < z3 < · · ·. The idea is now to define a narrowing operator
∆N that will force the sequence to stabilise when zi ≥ N for some fixed
of the form [−∞, zi ] the narrowing operator will force it to stabilise when
zi ≤ −N .
Formally, we shall define ∆ = ∆N by
(
⊥ if int1 = ⊥ ∨ int2 = ⊥
int1 ∆ int2 =
[z1 , z2 ] otherwise
where
(
inf(int1 ) if N < inf(int2 ) ∧ sup(int2 ) = ∞
z1 =
inf(int2 ) otherwise
(
sup(int1 ) if inf(int2 ) = −∞ ∧ sup(int2 ) < −N
z2 =
sup(int2 ) otherwise
[0, ∞], [1, ∞], [2, ∞], [3, ∞], [4, ∞], [5, ∞], · · ·
and assume that N = 3. Then the operator will give the sequence
([n, ∞]∆ )n :
[0, ∞], [1, ∞], [2, ∞], [3, ∞], [3, ∞], [3, ∞], · · ·
Galois Connections
Galois connections
γ:M →L
We shall write
(L, α, γ, M )
or γ
L
- M
α
We define (L, α, γ, M ) to be a Galois connection between the complete
lattices (L, v) and (M, v) if and only if
α : L → M and γ : M → L are monotone functions
that satisfy:
γ◦α w λl.l
α◦γ v λm.m
Let P(Z) = (P(Z), ⊆) be the complete lattice of sets of integers and let
Interval = (Interval, v) be the complete lattice of intervals. We shall now
define a Galois connection
Thus γZI will extract the set of elements described by the interval,
e.g. γZI ([0, 3]) = {0, 1, 2, 3} and γZI ([0, ∞]) = {z ∈ Z | z ≥ 0}.
The abstraction function αZI : P(Z) → Interval is defined by
(
⊥ if Z = ∅
αZI (Z) =
[inf 0 (Z), sup0 (Z)] otherwise
Thus αZI will determine the smallest interval that includes all the elements
of the set, e.g. αZI ({0, 1, 3}) = [0, 3] and αZI ({2 ∗ z | z > 0}) = [2, ∞].
Adjunctions
that satisfy
α(l) v m ⇔ l v γ(m)
(P(V ), α, γ, L)
γ(l) = {v ∈ V | β(v) v l}
for V 0 ⊆ V and l ∈ L.
Let us pause for a minute to see that this indeed defines an adjunction:
α(V 0 ) v l {β(v) | v ∈ V 0 } v l
F
⇔
⇔ ∀v ∈ V 0 : β(v) v l
⇔ V 0 ⊆ γ(l)
V
A special case of the above construction that is frequently useful is when
L = (P(D), ⊆) for some set D and we have an extraction function:
η : V → D.
We will then define the representation function βη : V → P(D) by
βη (v) = {η(v)} and the Galois connection between P(V ) and P(D) will
now be written
(P(V ), αη , γη , P(D))
where
η -
V D
Let us consider the two complete lattices (P(Z), ⊆) and (P(Sign), ⊆)
where Sign = {-, 0, +}.
• {-, 0, +}
• ∅
with
αsign (Z) = {sign(z) | z ∈ Z}
γsign (S) = {z ∈ Z | sign(z) ∈ S}
where Z ⊆ Z and S ⊆ Sign.
v S m iff v R (γ(m))
vSm ⇔ v R (γ(m))
⇔ β(v) v γ(m)
⇔ (α ◦ β)(v) v m
that satisfy:
γ◦α w λl.l
α◦γ = λm.m
the set of integers it describes and next use αZI to determine the smallest
interval containing this set and we get exactly the same interval as we
started with.
For a Galois connection (L, α, γ, M ) the following claims are equivalent:
Galois insertion.
Construction of Galois insertions
bound and the index). We shall proceed in two stages: First we shall ap-
and next we shall further approximate this difference using a finite lattice.
The two Galois connections will be defined by extraction functions and they
The abstraction and concretisation functions αdiff and γdiff will then be
for ZZ ⊆ Z × Z and Z ⊆ Z.
The second stage is specified by the Galois connection
<-1 if z < −1
if z = −1
-1
range(z) = 0 if z =0
+1 if z =1
>+1 if z >1
The abstraction and concretisation functions αrange and γrange will then be
This is the Galois connection specified by the extraction function range ◦ diff :
Z × Z → Range.
(L1 × L2 , α, γ, M1 × M2 )
where:
{(z, −z) | z ∈ Z} but in the present setting where we use P(Z) × P(Z) to
{(z, −z) | z ∈ Z} by (Z, Z) and hence the best property describing it will
be αSS (Z, Z) = ({-, 0, +}, {-, 0, +}). Thus we lose all information about the
(P(V1 × V2 ), α, γ, P(D1 × D2 ))
where
[
α(VV ) = {α1 ({v1 }) × α2 ({v2 }) | (v1 , v2 ) ∈ VV }
γ(DD) = {(v1 , v2 ) | α1 ({v1 }) × α2 ({v2 }) ⊆ DD}
where VV ⊆ V1 × V2 and DD ⊆ D1 × D2 .
It is instructive to see how the relational method is simplified if the Galois
connections (P(Vi ), αi , γi , P(Di )) are given by extraction functions
ηi : Vi → Di , i.e. if αi (Vi0 ) = {ηi (vi ) | vi ∈ Vi0 } and
γi (Di0 ) = {vi | ηi (vi ) ∈ Di0 }. We then have
has a value in {(z, −z) | z ∈ Z}. In the present setting {(z, −z) | z ∈ Z}
z ∈ Z}) = {(-, +), (0, 0), (+, -)} of P(Sign × Sign). Hence the information
α0 (f ) = α ◦ f
γ 0 (g) = γ◦g
L
α - M L γ
M
I I
f α0 (f ) γ 0 (g) g
S S
Monotone function space.
α(f ) = α2 ◦ f ◦ γ1
γ(g) = γ2 ◦ g ◦ α1
f γ(g)
L1 - L2 L1 - L2
6 6
γ1 α2 α1 γ2
? ?
M1 - M2 M1 - M2
α(f ) g
dealing with composite data. We shall now show how two analyses deal-
ing with the same data can be combined into one analysis; this amounts
(L, α, γ, M1 × M2 )
({(-, -), (0, 0), (+, +)}, {0, <-1}). Thus we do not exploit the fact that if the
(P(V ), α, γ, P(D1 × D2 ))
where V 0 ⊆ V and DD ⊆ D1 × D2 .
We will now get a Galois connection
where
(L, α, γ, ς[M1 × M2 ])
where
where
[
α(V 0 ) = {α1 ({v}) × α2 ({v}) | v ∈ V 0 }
γ(DD) = {v | α1 ({v}) × α2 ({v}) ⊆ DD}
\
ς(DD) = {DD0 | γ(DD) = γ(DD0 )}
We noted that the complete lattice P(Sign × Sign × Range) contains more
than one element that describes the empty set of P(Z × Z). The function
ςSSR0 will amount to
= γSSR0 (SSR0 )}
(-, -, <-1), (-, -, -1), (-, -, 0), (-, -, +1), (-, -, >+1),
(-, 0, +1), (-, 0, >+1),
(-, +, <-1), (-, +, -1), (-, +, 0), (-, +, +1), (-, +, >+1),
(0, -, <-1), (0, -, -1), (0, 0, 0), (0, +, <-1), (0, +, -1),
(+, -, <-1), (+, -, -1), (+, -, 0), (+, -, +1), (+, -, >+1),
(+, 0, +1), (+, 0, >+1),
(+, +, <-1), (+, +, -1), (+, +, 0), (+, +, +1), (+, +, >+1)
and they describe disjoint subsets of Z × Z. Let us call the above set of 29
elements for AB (for Array Bound); then ςSSR0 [P(Sign × Sign × Range)] is
isomorphic to P(AB).
To conclude the development of the complete lattice and the associated
Galois connection for the Array Bound Analysis we shall simply construct
the reduced tensor product of the Galois connections. This will yield a
Galois insertion isomorphic to
Note that from an implementation point of view the last step of the con-
struction has paid off: if we had stopped with the direct tensor product then
the properties would need 45 bits for their representation whereas now 29
bits suffice.
Summary. The Array Bound Analysis has been designed from three simple
Galois connections specified by extraction functions:
(i) an analysis approximating integers by their sign,
(ii) an analysis approximating pairs of integers by their difference in
magnitude, and
(iii) an analysis approximating integers by their closeness to 0, 1 and -1.
We have illustrated different ways of combining these analyses:
(iv) the relational product of analysis (i) with itself,
(v) the functional composition of analysis (ii) and (iii), and
(vi) the reduced tensor product of analysis (iv) and (v).
Induced Operations
α2 ◦ fp ◦ γ1 is a candidate for gp
fp
L1 - L2
6
γ1 α2
?
M1 - M2
α2 ◦ f p ◦ γ 1
We studied the simple program plus and specified the very precise
analysis
fplus (ZZ ) = {z1 + z2 | (z1 , z2 ) ∈ ZZ }
using the complete lattices (P(Z), ⊆) and (P(Z × Z), ⊆).
We introduced the Galois connection
gplus (SS)
= αsign (fplus (γSS0 (SS)))
= αsign (fplus ({(z1 , z2 ) ∈ Z × Z | (sign(z1 ), sign(z2 )) ∈ SS}))
= αsign ({z1 + z2 | z1 , z2 ∈ Z, (sign(z1 ), sign(z2 )) ∈ SS})
= {sign(z1 + z2 ) | z1 , z2 ∈ Z, (sign(z1 ), sign(z2 )) ∈ SS}
S
= {s1 ⊕ s2 | (s1 , s2 ) ∈ SS}
l1 ∇L l2 = γ(α(l1 ) ∇M α(l2 ))
l1 ∇L l2 = γ(α(l1 ) ∇M α(l2 ))
Acknowledgements
Thank you