Document

advertisement
Spring 2015
Program Analysis and Verification
Lecture 6: Axiomatic Semantics III
Roman Manevich
Ben-Gurion University
Tentative syllabus
Semantics
Static
Analysis
Abstract
Interpretation
fundamentals
Analysis
Techniques
Crafting your
own
Natural
Semantics
Automating
Hoare Logic
Lattices
Numerical
Domains
Soot
Structural
semantics
Control Flow
Graphs
Fixed-Points
Alias analysis
From proofs
to abstractions
Axiomatic
Verification
Equation
Systems
Chaotic
Iteration
Interprocedural
Analysis
Systematically
developing
transformers
Collecting
Semantics
Galois
Connections
Shape
Analysis
Domain
constructors
CEGAR
Widening/
Narrowing
2
Previously
• Hoare logic
– Inference system
– Annotated programs
– Soundness and completeness
• Weakest precondition calculus
• Strongest postcondition calculus
3
Weakest (liberal) precondition rules
1.
2.
3.
4.
wlp(skip, Q) = Q
wlp(x := a, Q) = Q[a/x]
wlp(S1; S2, Q) = wlp(S1, wlp(S2, Q))
wlp(if b then S1 else S2, Q) =
(b wlp(S1, Q))
( b wlp(S2, Q))
5. wlp(while b do { } S, Q) =
where {b
}S{ }
and b
 Q Use consequence
rule here
4
Strongest postcondition rules
1.
2.
3.
4.
sp(skip, P) = P
sp(x := a, P) = v. x=a[v/x] P[v/x]
sp(S1; S2, P) = sp(S2, sp(S1, P))
sp(if b then S1 else S2, P) =
sp(S1, b P) sp(S2, b P)
5. sp(while b do { } S, P) =
b
where {b
}S{ }
and P  b
Use consequence
rule here
5
Warm-up
6
Proof of swap by WP
{
t
{
x
{
y
{
y=b
:= x
y=b
:= y
x=b
:= t
x=b
x=a }
t=a }
t=a }
y=a }
7
Prove swap via SP
{ y=b
t := x
{
x=a
}
}
x := y
{
}
y := t
{ x=b
y=a
}
8
Prove swap via SP
Quantifier
elimination
(a very trivial one)
Quantifier
elimination
Quantifier
elimination
{ y=b
x=a }
t := x
{ v. t=x y=b x=a }
x := y
{ v. x=y t=v y=b v=a }
{ x=y y=b
v. t=v v=a }
{ x=y y=b t=a }
y := t
{ v. y=t x=v v=b t=a }
{ y=t t=a
v. x=v v=b }
{ y=t t=a x=b }
{ x=b
y=a }
9
Proof of absolute value via WP
{ x=v
{ (-x=|v|
x<0)
if x<0 then
{ -x=|v|
x := -x
{ x=|v|
else
{ x=|v|
skip
{ x=|v|
{ x=|v|
(x=|v|
}
x 0) }
}
}
}
}
}
10
Prove absolute value by SP
{ x=v }
{
if x<0 then
{
x := -x
{
else
{
skip
{
{
{ x=|v| }
}
}
}
}
}
}
11
Proof of absolute value via WP
{ x=v }
if x<0 then
{ x=v
x<0 }
x := -x
{ w. x=-w
w=v
w<0 }
{ x=-v
v<0 }
else
{ x=v
x 0 }
skip
{ x=v
x 0 }
{ x=-v
v<0
x=v
x 0 }
{ x=|v| }
12
Agenda
• Some useful rules
• Extension for memory
• Proving termination
13
Making the proof system
more practical
14
Conjunction rule
{P}S{Q}
{ P’ } S { Q’ }
[conjp]
{ P P’ } S {Q Q’ }
• Allows breaking up proofs into smaller, easier
to manage, sub-proofs
15
Breaks if C is nondeterministic
More useful rules
{P}C{Q}
{ P’ } C { Q’ }
[disjp]
{ P P’ } C {Q Q’ }
{P}C{Q}
[existp] { v. P } C { v. Q v FV(C
}
)
{P}C{Q}
v FV(C
[univp]
{ v. P } C { v. Q }
)
[Invp] { F } C { F } Mod(C) FV(F)={}
• Mod(C) = set of variables assigned to in sub-statements of C
• FV(F) = free variables of F
16
Invariance + Conjunction = Constancy
{P}C{Q}
[constancyp]
Mod(C)
{F P}C{F Q}
FV(F)={}
• Mod(C) = set of variables assigned to in sub-statements of C
• FV(F) = free variables of F
17
Strongest
postcondition
calculus
practice
By Vadim Plessky (http://svgicons.sourceforge.net/) [see page for license], via Wikimedia Commons
18
Floyd’s strongest postcondition rule
{ P } x := a { v. x=a[v/x] P[v/x]
[assFloyd]
}
where v is a fresh variable
The value of x
in the pre-state
• Example
{ z=x } x:=x+1 {
?
}
19
Floyd’s strongest postcondition rule
{ P } x := a { v. x=a[v/x] P[v/x]
[assFloyd]
}
where v is a fresh variable
meaning: {x=z+1}
• Example
{ z=x } x:=x+1 {
v. x=v+1 z=v
}
• This rule is often considered problematic
because it introduces a quantifier – needs to
be eliminated further on
• We will now see a variant of this rule
20
“Small” assignment axiom
Create an explicit Skolem
variable in precondition
Then assign the resulting
value to x
First evaluate a
in the precondition state
(as a may access x)
[assfloyd] { x=v } x:=a { x=a[v/x] }
where v FV(a)
• Examples:
{x=n} x:=5*y {x=5*y}
{x=n} x:=x+1 {x=n+1}
{x=n} x:=y+1 {x=y+1}
[existp] { n. x=n} x:=y+1 { n. x=y+1} therefore {true} x:=y+1 {x=y+1}
[constancyp] {z=9} x:=y+1 {z=9 x=y+1}
21
“Small” assignment axiom
[assfloyd] { x=v } x:=a { x=a[v/x] }
where v FV(a)
• Examples:
{x=n} x:=5*y {x=5*y}
{x=n} x:=x+1 {x=n+1}
{x=n} x:=y+1 {x=y+1}
[existp] { n. x=n} x:=y+1 { n. x=y+1} therefore {true} x:=y+1 {x=y+1}
[constancyp] {z=9} x:=y+1 {z=9 x=y+1}
22
“Small” assignment axiom
[assfloyd] { x=v } x:=a { x=a[v/x] }
where v FV(a)
• Examples:
{x=n} x:=5*y {x=5*y}
{x=n} x:=x+1 {x=n+1}
{x=n} x:=y+1 {x=y+1}
[existp] { n. x=n} x:=y+1 { n. x=y+1} therefore {true} x:=y+1 {x=y+1}
[constancyp] {z=9} x:=y+1 {z=9 x=y+1}
23
“Small” assignment axiom
[assfloyd] { x=v } x:=a { x=a[v/x] }
where v FV(a)
• Examples:
{x=n} x:=5*y {x=5*y}
{x=n} x:=x+1 {x=n+1}
{x=n} x:=y+1 {x=y+1}
[existp] { n. x=n} x:=y+1 { n. x=y+1} therefore {true} x:=y+1 {x=y+1}
[constancyp] {z=9} x:=y+1 {z=9 x=y+1}
24
Prove using strongest postcondition
{ x=a
t := x
y=b }
x := y
y := t
{ x=b
y=a }
25
Prove using strongest postcondition
{ x=a
t := x
{ x=a
y=b }
y=b
t=a }
x := y
y := t
{ x=b
y=a }
26
Prove using strongest postcondition
{ x=a
t := x
{ x=a
x := y
{ x=b
y=b }
y=b
t=a }
y=b
t=a }
y := t
{ x=b
y=a }
27
Prove using strongest postcondition
{ x=a
t := x
{ x=a
y=b }
y=b
t=a }
x := y
{ x=b
y=b
t=a }
y := t
{ x=b
{ x=b
y=a
t=a }
y=a } // cons
28
Prove using strongest postcondition
{ x=v }
if x<0 then
{ x=v
x<0 }
x := -x
{ x=-v
x>0 }
else
{ x=v
x 0 }
skip
{ x=v
x 0 }
{ v<0
x=-v
v 0
{ x=|v| }
x=v }
29
Prove using strongest postcondition
{ x=v }
if x<0 then
{ x=v
x<0 }
x := -x
{ x=-v
x>0 }
else
{ x=v
x 0 }
skip
{ x=v
x 0 }
{ v<0
x=-v
v 0
{ x=|v| }
x=v }
30
Sum program – specify
• Define Sum(0, n) = 0+1+…+n
{
?
x := 0
res := 0
while (x<y) do
res := res+x
x := x+1
{
?
{ x=Sum(0, n) } { y=n+1 }
{ x+y=Sum(0, n+1) }
}
Background axiom
}
31
Sum program – specify
• Define Sum(0, n) = 0+1+…+n
{ y 0 }
x := 0
res := 0
while (x<y) do
res := res+x
x := x+1
{ res = Sum(0, y) }
{ x=Sum(0, n) } { y=n+1 }
{ x+y=Sum(0, n+1) }
Background axiom
32
Sum program – prove
• Define Sum(0, n) = 0+1+…+n
{ x=Sum(0, n) } { y=n+1 }
{ x+y=Sum(0, n+1) }
{ y 0 }
x := 0
res := 0
Inv =
while (x<y) do
res := res+x
x := x+1
{ res = Sum(0, y) }
33
Sum program – prove
• Define Sum(0, n) = 0+1+…+n
{ x=Sum(0, n) } { y=n+1 }
{ x+y=Sum(0, n+1) }
{ y 0 }
x := 0
{ y 0
x=0 }
res := 0
Inv =
while (x<y) do
res := res+x
x := x+1
{ res = Sum(0, y) }
34
Sum program – prove
• Define Sum(0, n) = 0+1+…+n
{ x=Sum(0, n) } { y=n+1 }
{ x+y=Sum(0, n+1) }
{ y 0 }
x := 0
{ y 0
x=0 }
res := 0
{ y 0
x=0
res=0 }
Inv =
while (x<y) do
res := res+x
x := x+1
{ res = Sum(0, y) }
35
Sum program – prove
• Define Sum(0, n) = 0+1+…+n
{ y 0 }
x := 0
{ y 0
x=0 }
res := 0
{ y 0
x=0
res=0 }
Inv = { y 0
res=Sum(0, x)
while (x<y) do
x y
{ x=Sum(0, n) } { y=n+1 }
{ x+y=Sum(0, n+1) }
}
res := res+x
x := x+1
{ res = Sum(0, y) }
36
Sum program – prove
• Define Sum(0, n) = 0+1+…+n
{ x=Sum(0, n) } { y=n+1 }
{ x+y=Sum(0, n+1) }
{ y 0 }
x := 0
{ y 0
x=0 }
res := 0
{ y 0
x=0
res=0 }
Inv = { y 0
res=Sum(0, x)
x y
}
while (x<y) do
{ y 0
res=m
x=n
n y
m=Sum(0, n)
x<y }
{ y 0
res=m
x=n
m=Sum(0, n)
n<y }
res := res+x
x := x+1
{ res = Sum(0, y) }
37
Sum program – prove
• Define Sum(0, n) = 0+1+…+n
{ x=Sum(0, n) } { y=n+1 }
{ x+y=Sum(0, n+1) }
{ y 0 }
x := 0
{ y 0
x=0 }
res := 0
{ y 0
x=0
res=0 }
Inv = { y 0
res=Sum(0, x)
x y
}
while (x<y) do
{ y 0
res=m
x=n
n y
m=Sum(0, n)
x<y }
{ y 0
res=m
x=n
m=Sum(0, n)
n<y }
res := res+x
{ y 0
res=m+x
x=n
m=Sum(0, n)
n<y
}
x := x+1
{ res = Sum(0, y) }
38
Sum program – prove
• Define Sum(0, n) = 0+1+…+n
{ x=Sum(0, n) } { y=n+1 }
{ x+y=Sum(0, n+1) }
{ y 0 }
x := 0
{ y 0
x=0 }
res := 0
{ y 0
x=0
res=0 }
Inv = { y 0
res=Sum(0, x)
x y
}
while (x<y) do
{ y 0
res=m
x=n
n y
m=Sum(0, n)
x<y }
{ y 0
res=m
x=n
m=Sum(0, n)
n<y }
res := res+x
{ y 0
res=m+x
x=n
m=Sum(0, n)
n<y
}
x := x+1
{ y 0
res=m+x
x=n+1
m=Sum(0, n)
n<y
}
{ y 0
res=Sum(0, x)
x=n+1
n<y } // sum axiom
{ y 0
res=Sum(0, x)
x y } // cons
{ res = Sum(0, y) }
39
Sum program – prove
• Define Sum(0, n) = 0+1+…+n
{ x=Sum(0, n) } { y=n+1 }
{ x+y=Sum(0, n+1) }
{ y 0 }
x := 0
{ y 0
x=0 }
res := 0
{ y 0
x=0
res=0 }
Inv = { y 0
res=Sum(0, x)
x y
}
while (x<y) do
{ y 0
res=m
x=n
n y
m=Sum(0, n)
x<y }
{ y 0
res=m
x=n
m=Sum(0, n)
n<y }
x := x+1
{ y 0
res=m
x=n+1
m=Sum(0, n)
n<y
}
res := res+x
{ y 0
res=m+x
x=n+1
m=Sum(0, n)
n<y
}
{ y 0
res=Sum(0, x)
x=n+1
n<y } // sum axiom
{ y 0
res=Sum(0, x)
x y } // cons
{ y 0
res=Sum(0, x)
x y
x y }
{ y 0
res=Sum(0, y)
x=y }
{ res = Sum(0, y) }
40
Buggy sum program 1
• Define Sum(0, n) = 0+1+…+n
{ x=Sum(0, n) } { y=n+1 }
{ x+y=Sum(0, n+1) }
{ y 0 }
x := 0
{ y 0
x=0 }
res := 0
{ y 0
x=0
res=0 }
Inv = { y 0
res=Sum(0, x)
x y
}
while (x<y) do
{ y 0
res=m
x=n
n y
m=Sum(0, n)
x<y }
{ y 0
res=m
x=n
m=Sum(0, n)
n<y }
res := res+x
{ y 0
res=m+x
x=n
m=Sum(0, n)
n<y
}
x := x+1
{ y 0
res=m+n
x=n+1
m=Sum(0, n)
n<y
}
{ y 0
res=Sum(0, n)+n
x=n+1
n<y }
{ y 0
res=Sum(0, x)
x y } // cons
{ y 0
res=Sum(0, x)
x y
x y }
{ y 0
res=Sum(0, y)
x=y }
{ res = Sum(0, y) }
41
Buggy sum program 2
{ y 0 }
x := 0
{ y 0
x=0 }
res := 0
{ y 0
x=0
res=0 }
Inv = { y 0
res=Sum(0, x) }
= { y 0
res=m
x=n
m=Sum(0, n) }
while (x y) do
{ y 0
res=m
x=n
m=Sum(0, n)
x y
n y }
x := x+1
{ y 0
res=m
x=n+1
m=Sum(0, n)
n y}
res := res+x
{ y 0
res=m+x
x=n+1
m=Sum(0, n)
n y}
{ y 0
res-x=Sum(0, x-1)
n y}
{ y 0
res=Sum(0, x) }
{ y 0
res=Sum(0, x)
{res = Sum(0, y) }
x>y }
42
Handling data structures
43
Problems with Hoare logic and heaps
• { P[a/x] } x := a { P }
• Consider the annotated program
{ y=5 }
y := 5;
The rule works on a syntactic
level unaware of possible
{ y=5 }
aliasing between different
x := &y;
terms (y and *x in our case)
{ y=5 }
*x := 7;
{ y=5 }
• Is it correct?
44
Problems with Hoare logic and heaps
• { P[a/x] } x := a { P }
• {(x=&y
z=5)
(x&y
y=5)}
*x = z;
{ y=5 }
• What should the precondition be?
45
Problems with Hoare logic and heaps
• { P[a/x] } x := a { P }
• {(x=&y
z=5)
(x&y
y=5)}
*x = z;
{ y=5 }
• We split into cases depending on possible aliasing
46
Problems with Hoare logic and heaps
• { P[a/x] } x := a { P }
• {(x=&y
z=5)
(x&y
y=5)}
*x = z;
{ y=5 }
• What should the precondition be?
• Joseph M. Morris: A General Axiom of
Assignment
• A different approach: heaps as arrays
• Really successful approach for heaps is based on
Separation Logic
47
Axiomatizing data types
S ::= x := a | x := y[a] | y[a] := x
| skip | S1; S2
| if b then S1 else S2
| while b do S
• We added a new type of variables – array variables
– Model array variable as a function y : Z  Z
• Re-define program states
State =
• Define operational semantics
x := y[a],  
y[a] := x,  
48
Axiomatizing data types
S ::= x := a | x := y[a] | y[a] := x
| skip | S1; S2
| if b then S1 else S2
| while b do S
• We added a new type of variables – array
variables
– Model array variable as a function y : Z  Z
• We need the two following axioms:
{ y[x a](x) = a }
{ zx  y[x a](z) = y(z) }
49
Array update rules (wlp)
S ::= x := a | x := y[a] | y[a] := x
| skip | S1; S2
A very general approach – allows
| if b then S1 else S2 handling many data types
| while b do S
• Treat an array assignment y[a] := x as an
update to the array function y
– y := y[a x] meaning y’= v. v=a ? x : y(v)
[array-update] { P[y[a x]/y] } y[a] := x { P }
[array-load] { P[y(a)/x] } x := y[a] { P }
50
Array update rules (wlp) example
• Treat an array assignment y[a] := x as an
update to the array function y
– y := y[a x] meaning y’= v. v=a ? x : y(v)
[array-update] { P[y[a x]/y] } y[a] := x { P }
{x=y[i 7](i)} y[i]:=7 {x=y(i)}
{x=7} y[i]:=7 {x=y(i)}
[array-load] { P[y(a)/x] } x := y[a] { P }
{y(a)=7} x:=y[a] {x=7}
51
Array update rules (sp)
In both rules
v, g, and b are fresh
[array-updateF] { x=v
[array-loadF] { y=g
y=g a=b } y[a] := x { y=g[b v]
}
a=b } x := y[a] { x=g(b) }
52
practice proving programs
with arrays
53
Array-max program – specify
nums : array
N : int // N stands for num’s length
{ N 0
nums=orig_nums }
x := 0
res := nums[0]
while x < N
if nums[x] > res then
res := nums[x]
x := x + 1
1. { x=N }
2. { m. (m 0
m<N)  nums(m) res }
3. { m. m 0
m<N
nums(m)=res }
4. { nums=orig_nums }
54
Array-max program
nums : array
N : int // N stands for num’s length
{ N 0
nums=orig_nums }
x := 0
res := nums[0]
while x < N
if nums[x] > res then
res := nums[x]
x := x + 1
Post1: { x=N }
Post2: { nums=orig_nums }
Post3: { m. 0 m<N  nums(m) res }
Post4: { m. 0 m<N
nums(m)=res }
55
Proof strategy
• Prove each goal 1, 2, 3, 4 separately and use
conjunction rule to prove them all
• After proving
– {N 0} C {x=N}
– {nums=orig_nums} C {nums=orig_nums}
• We have proved
– {N 0
{x=N
nums=orig_nums}
C
nums=orig_nums}
• We can refer to assertions from earlier proofs in
writing new proofs
56
Array-max example: Post1
nums : array
N : int // N stands for num’s length
{ N 0 }
x := 0
{ N 0
x=0 }
res := nums[0]
{ x=0 }
Inv = { x N }
while x < N
{ x=k
k<N }
if nums[x] > res then
{ x=k
k<N }
res := nums[x]
{ x=k
k<N }
{ x=k
k<N }
x := x + 1
{ x=k+1
k<N }
{ x N
x N }
{ x=N }
57
Array-max example: Post2
nums : array
N : int // N stands for num’s length
{ nums=orig_nums }
x := 0
{ nums=orig_nums }
res := nums[0]
{ nums=orig_nums }
Inv = { nums=orig_nums }
while x < N
{ nums=orig_nums
x < N }
if nums[x] > res then
{ nums=orig_nums }
res := nums[x]
{ nums=orig_nums }
{ nums=orig_nums }
x := x + 1
{ nums=orig_nums }
{ nums=orig_nums
x N }
{ nums=orig_nums }
58
Array-max example: Post3
nums : array
{ N 0
0 m<N } // N stands for num’s length
x := 0
{ x=0 }
res := nums[0]
{ x=0
res=nums(0) }
Inv = { 0 m<x  nums(m) res }
while x < N
{ x=k
res=oRes
0 m<k  nums(m) oRes }
if nums[x] > res then
{ nums(x)>oRes
res=oRes
x=k
0 m<k  nums(m) oRes }
res := nums[x]
{ res=nums(x)
nums(x)>oRes
x=k
0 m<k  nums(m) oRes }
{ x=k
0 m k  nums(m) res }
{ (x=k
0 m k  nums(m) res)
(oRes nums(x)
res=oRes
x=k
res=oRes
0 m<k 
nums(m) oRes)}
{ x=k
0 m k  nums(m) res }
x := x + 1
{ x=k+1
0 m k  nums(m) res }
{ 0 m<x  nums(m) res }
{ x=N
0 m<x  nums(m) res}
[univp]{ m. 0 m<N  nums(m) res }
59
Proving
termination
By Noble0 (Own work) [CC BY-SA 3.0
(http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons
60
Total correctness semantics for While
[assp] [ P[a/x] ] x := a [ P ]
[skipp] [ P ] skip [ P ]
[ P ] S1 [ Q ], [ Q ] S2 [ R ]
[compp]
[ P ] S1; S2 [ R ]
[b
[ifp]
[whilep]
[consp]
P ] S1 [ Q ], [ b P ] S2 [ Q
]
[ P ] if b then S1 else S2 [ Q ]
[ P(z+1) ] S [ P(z) ]
P(z+1)  b
[ z. P(z) ] while b do S [ P(0) ] P(0)  b
[ P’ ] S [ Q’ ]
[P]S[Q]
if P P’ and Q’ Q
61
Total correctness semantics for While
[assp] [ P[a/x] ] x := a [ P ]
[skipp] [ P ] skip [ P ]
[ P ] S1 [ Q ], [ Q ] S2 [ R ]
[compp]
[ P ] S1; S2 [ R ]
[b
Rank, or
Loop
variant
[ifp]
[whilep]
[consp]
P ] S1 [ Q ], [ b P ] S2 [ Q
]
[ P ] if b then S1 else S2 [ Q ]
[ b P t=k ] S [ P t<k ]
P  t0
[ P ] while b do S [ b P ]
[ P’ ] S [ Q’ ]
[P]S[Q]
if P P’ and Q’ Q
62
Proving termination
• There is a more general rule based on wellfounded relations
– Partial orders with no infinite strictly decreasing
chains
• Exercise: write a rule that proves only that a
program S, started with precondition P
terminates
[
]S[
]
63
Proving termination
• There is a more general rule based on wellfounded relations
– Partial orders with no infinite strictly decreasing
chains
• Exercise: write a rule that proves only that a
program S, started with precondition P
terminates
[ P ] S [ true ]
64
Array-max – specify termination
nums : array
N : int // N stands for num’s length
x := 0
res := nums[0]
Variant = [
?
]
while x < N
if nums[x] > res then
res := nums[x]
x := x + 1
[
?
]
65
Array-max – specify termination
nums : array
N : int // N stands for num’s length
x := 0
res := nums[0]
Variant = [ N-x ]
while x < N
[
?
]
if nums[x] > res then
res := nums[x]
x := x + 1
[
?
]
[ true ]
66
Array-max – prove loop variant
nums : array
N : int // N stands for num’s length
x := 0
res := nums[0]
Variant = [ t=N-x ]
while x < N
[ x<N
N-x=k
N-x0 ]
if nums[x] > res then
res := nums[x]
x := x + 1
// [ N-x<k
N-x0 ]
[ true ]
67
Array-max – prove loop variant
nums : array
N : int // N stands for num’s length
x := 0
res := nums[0]
Capture initial value of x, since
Variant = [ t=N-x ]
it changes in the loop
while x < N
[ x=x0
x0<N
N-x0=k
N-x00 ]
if nums[x] > res then
res := nums[x]
x := x + 1
// [ N-x<k
N-x0 ]
[ true ]
68
Array-max – prove loop variant
nums : array
N : int // N stands for num’s length
x := 0
res := nums[0]
Variant = [ t=N-x ]
while x < N
[ x=x0
x0<N
N-x0=k
N-x00 ]
if nums[x] > res then
res := nums[x]
[ x=x0
x0<N
N-x0=k
N-x00 ] // Frame
x := x + 1
// [ N-x<k
N-x0 ]
[ true ]
69
Array-max – prove loop variant
nums : array
N : int // N stands for num’s length
x := 0
res := nums[0]
Variant = [ t=N-x ]
while x < N
[ x=x0
x0<N
N-x0=k
N-x00 ]
if nums[x] > res then
res := nums[x]
[ x=x0
x0<N
N-x0=k
N-x00 ] // Frame
x := x + 1
[ x=x0+1
x0<N
N-x0=k
N-x00 ]
// [ N-x<k
N-x0 ]
[ true ]
70
Array-max – prove loop variant
nums : array
N : int // N stands for num’s length
x := 0
res := nums[0]
Variant = [ t=N-x ]
while x < N
[ x=x0
x0<N
N-x0=k
N-x00 ]
if nums[x] > res then
res := nums[x]
[ x=x0
x0<N
N-x0=k
N-x00 ] // Frame
x := x + 1
[ x=x0+1
x0<N
N-x0=k
N-x00 ]
[ N-x<k
N-x0 ] // cons
[ true ]
71
Zune calendar bug
while (days > 365) {
if (IsLeapYear(year)) {
if (days > 366) {
days -= 366;
year += 1;
}
} else {
days -= 365;
year += 1;
}
}
72
Fixed code
while (days > 365) {
if (IsLeapYear(year)) {
if (days > 366) {
days -= 366;
year += 1;
}
else {
break;
}
} else {
days -= 365;
year += 1;
}
}
73
Fixed code – specify termination
[ ? ]
while (days > 365) {
if (IsLeapYear(year)) {
if (days > 366) {
days -= 366;
year += 1;
}
else {
break;
}
} else {
days -= 365;
year += 1;
}
}
[ ? ]
74
Fixed code – specify variant
[ true ]
Variant = [ ? ]
while (days > 365) {
if (IsLeapYear(year)) {
if (days > 366) {
days -= 366;
year += 1;
}
else {
break;
}
} else {
days -= 365;
year += 1;
}
[
?
]
}
[ true ]
75
Fixed code – proving termination
[ true ]
Variant = [ t=days ]
while (days > 365) {
[ days>365
days=k
days0 ]
if (IsLeapYear(year)) {
if (days > 366) {
days -= 366;
year += 1;
}
else {
break; [ false ]
}
} else {
days -= 365;
year += 1;
}
// [ days0
days<k ]
}
[ true ]
Let’s model break by a
small cheat – assume
execution never gets
past it
76
Fixed code – proving termination
[ true ]
Variant = [ t=days ]
while (days > 365) {
[ days0
k=days
days>365 ] -> [ days0
k=days
days>365 ]
if (IsLeapYear(year)) {
[ k=days
days>365 ]
if (days > 366) {
[ k=days
days>365
days>366 ] -> [ k=days
days>366 ]
days -= 366;
[ days=k-366
days>0 ]
year += 1;
[ days=k-366
days>0 ]
}
else {
[ k=days
days>365
days366 ]
break; [ false ]
}
[ (days=k-366
days>0)
false ] -> [ days<k
days>0 ]
} else {
[ k=days
days>365 ]
days -= 365;
[ k-365=days
days-365>365 ] -> [ k-365=days
days0 ] -> [ days<k
year += 1;
[ days<k
days0 ]
}
[ days<k
days0 ]
}
[ true ]
days0 ]
77
Challenge: proving non-termination
• Write a rule for proving that a program does
not terminate when started with a
precondition P
• Prove that the buggy Zune calendar program
does not terminate
[while-ntp]
{b P}S{b}
{ P } while b do S { false }
78
conclusion
79
Extensions to axiomatic semantics
• Assertions for execution time
– Exact time
– Order of magnitude time
• Assertions for dynamic memory
– Separation Logic
• Assertions for parallelism
– Owicki-Gries
– Concurrent Separation Logic
– Rely-guarantee
80
Axiomatic verification conclusion
• Very powerful technique for reasoning about
programs
– Sound and complete
• Extendible
• Static analysis can be used to automatically
synthesize assertions and loop invariants
81
Next lecture:
static analysis
Download