Spring 2016 Program Analysis and Verification

Slides:



Advertisements
Similar presentations
Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
Advertisements

ICE1341 Programming Languages Spring 2005 Lecture #6 Lecture #6 In-Young Ko iko.AT. icu.ac.kr iko.AT. icu.ac.kr Information and Communications University.
Reasoning About Code; Hoare Logic, continued
Hoare’s Correctness Triplets Dijkstra’s Predicate Transformers
11111 Functional Program Verification CS 4311 A. M. Stavely, Toward Zero Defect Programming, Addison-Wesley, Y. Cheon and M. Vela, A Tutorial on.
David Evans CS655: Programming Languages University of Virginia Computer Science Lecture 19: Minding Ps & Qs: Axiomatic.
Axiomatic Verification I Prepared by Stephen M. Thebaut, Ph.D. University of Florida Software Testing and Verification Lecture 17.
Predicate Transformers
Program Proving Notes Ellen L. Walker.
Program Analysis and Verification Spring 2014 Program Analysis and Verification Lecture 5: Axiomatic Semantics II Roman Manevich Ben-Gurion University.
1 Operational Semantics Mooly Sagiv Tel Aviv University Textbook: Semantics with Applications.
Floyd Hoare Logic. Semantics A programming language specification consists of a syntactic description and a semantic description. Syntactic description:symbols.
Proving Program Correctness The Axiomatic Approach.
Program Analysis and Verification Noam Rinetzky Lecture 3: Axiomatic Semantics 1 Slides credit: Roman Manevich, Mooly Sagiv, Eran Yahav.
Program Analysis and Verification
Program Analysis and Verification Spring 2014 Program Analysis and Verification Lecture 7: Static Analysis I Roman Manevich Ben-Gurion University.
Reading and Writing Mathematical Proofs
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 2: Operational Semantics I Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 14: Numerical Abstractions Roman Manevich Ben-Gurion University.
1 Formal Semantics of Programming Languages “Program testing can be used to show the presence of bugs, but never to show their absence!” --Dijkstra.
Program Analysis and Verification Spring 2014 Program Analysis and Verification Lecture 14: Numerical Abstractions Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 9: Abstract Interpretation I Roman Manevich Ben-Gurion University.
Program Analysis and Verification
Program Analysis and Verification Spring 2014 Program Analysis and Verification Lecture 4: Axiomatic Semantics I Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 12: Abstract Interpretation IV Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 4: Axiomatic Semantics I Roman Manevich Ben-Gurion University.
Principle of Programming Lanugages 3: Compilation of statements Statements in C Assertion Hoare logic Department of Information Science and Engineering.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 13: Abstract Interpretation V Roman Manevich Ben-Gurion University.
Cs7100(Prasad)L18-9WP1 Axiomatic Semantics Predicate Transformers.
Program Analysis and Verification Noam Rinetzky Lecture 5: Abstract Interpretation 1 Slides credit: Roman Manevich, Mooly Sagiv, Eran Yahav.
CSC3315 (Spring 2009)1 CSC 3315 Languages & Compilers Hamid Harroud School of Science and Engineering, Akhawayn University
Program Analysis and Verification
Program Analysis and Verification Spring 2014 Program Analysis and Verification Lecture 8: Static Analysis II Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2014 Program Analysis and Verification Lecture 6: Axiomatic Semantics III Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 6: Axiomatic Semantics III Roman Manevich Ben-Gurion University.
CORRECTNESS ISSUES AND LOOP INVARIANTS Lecture 8 CS2110 – Fall 2014.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 8: Static Analysis II Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2016 Program Analysis and Verification Lecture 5: Axiomatic Semantics II Roman Manevich Ben-Gurion University.
Spring 2017 Program Analysis and Verification
Spring 2017 Program Analysis and Verification
Spring 2016 Program Analysis and Verification
Spring 2016 Program Analysis and Verification
Spring 2017 Program Analysis and Verification
Spring 2016 Program Analysis and Verification
Spring 2016 Program Analysis and Verification
Warm-up exercises Define program state: Define state predicate:
Reasoning About Code.
Reasoning about code CSE 331 University of Washington.
Program Analysis and Verification
Predicate Transforms II
Spring 2016 Program Analysis and Verification
Spring 2017 Program Analysis and Verification Operational Semantics
Predicate Transforms I
Lecture 5 Floyd-Hoare Style Verification
Program Analysis and Verification
Axiomatic semantics Points to discuss: The assignment statement
Programming Languages and Compilers (CS 421)
Programming Languages 2nd edition Tucker and Noonan
Predicate Transformers
Functional Program Verification
Formal Methods in software development
Predicate Transforms I
Predicate Transforms II
The Zoo of Software Security Techniques
Program correctness Axiomatic semantics
Program Verification with Hoare Logic
Spring 2016 Program Analysis and Verification Operational Semantics
Programming Languages and Compilers (CS 421)
Programming Languages 2nd edition Tucker and Noonan
Strongest postcondition rules
Presentation transcript:

Spring 2016 Program Analysis and Verification Lecture 5: Axiomatic Semantics III Roman Manevich Ben-Gurion University

Tentative syllabus Program Verification Program Analysis Basics Operational semantics Hoare Logic Applying Hoare Logic Weakest Precondition Calculus Proving Termination Data structures Program Analysis Basics Control Flow Graphs Equation Systems Collecting Semantics Using Soot Abstract Interpretation fundamentals Lattices Fixed-Points Chaotic Iteration Galois Connections Domain constructors Widening/ Narrowing Analysis Techniques Numerical Domains Alias analysis Interprocedural Analysis Shape Analysis CEGAR

Previously Hoare logic Weakest precondition calculus Inference system Annotated programs Soundness and completeness Weakest precondition calculus Strongest postcondition calculus

Weakest (liberal) precondition rules 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)) wlp(while b do {} S, Q) =  where {b  } S {} and b    Q Inv  ((Inv  b)  wp(S, Inv))  ((Inv  b)  Q) Parameterized by the loop invariant Inv

Strongest postcondition rules 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) sp(while b do {} S, P) =   b where {b  } S {} and P  b   Inv  ((Inv  b)  wp(S, Inv))  ((Inv  b)  Q) Parameterized by the loop invariant Inv

Warm-up

Proof of swap by WP { y=b  x=a } t := x { y=b  t=a } x := y { x=b  t=a } y := t { x=b  y=a }

Prove swap via SP { y=b  x=a } t := x { } x := y { } y := t { x=b  y=a }

Prove swap via SP { 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 } Quantifier elimination (a very trivial one) Quantifier elimination Quantifier elimination

Proof of absolute value via WP { x=v } { (-x=|v|  x<0)  (x=|v|  x0) } if x<0 then { -x=|v| } x := -x { x=|v| } else { x=|v| } skip { x=|v| } { x=|v| }

Prove absolute value by SP { x=v } { } if x<0 then { } x := -x { } else { } skip { } { } { x=|v| }

Proof of absolute value via SP { 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| }

Agenda Some useful rules Extension for memory Proving termination

Making the proof system more practical

{ P } S { Q } { P’ } S { Q’ } { P  P’ } S {Q  Q’ } Conjunction rule { P } S { Q } { P’ } S { Q’ } { P  P’ } S {Q  Q’ } [conjp] Allows breaking up proofs into smaller, easier to manage, sub-proofs

More useful rules [Invp] Breaks if C is non-deterministic { P } C { Q } { P’ } C { Q’ } { P  P’ } C {Q  Q’ } [disjp] { P } C { Q } { v. P } C { v. Q } [existp] vFV(C) { P } C { Q } {v. P } C {v. Q } [univp] vFV(C) { F } C { F } Mod(C)  FV(F)={} [Invp] Mod(C) = set of variables assigned to in sub-statements of C FV(F) = free variables of F

Invariance + Conjunction = Constancy { P } C { Q } { F  P } C { F  Q } [constancyp] Mod(C)  FV(F)={} Mod(C) = set of variables assigned to in sub-statements of C FV(F) = free variables of F

Strongest postcondition calculus practice By Vadim Plessky (http://svgicons.sourceforge.net/) [see page for license], via Wikimedia Commons

Floyd’s strongest postcondition rule { P } x := a { v. x=a[v/x]  P[v/x] } where v is a fresh variable [assFloyd] The value of x in the pre-state Example { z=x } x:=x+1 { ? }

Floyd’s strongest postcondition rule { P } x := a { v. x=a[v/x]  P[v/x] } where v is a fresh variable [assFloyd] 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

“Small” assignment axiom First evaluate a in the precondition state (as a may access x) Create an explicit Skolem variable in precondition Then assign the resulting value to 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}

“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}

“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}

“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}

Prove using strongest postcondition { x=a  y=b } t := x x := y y := t { x=b  y=a }

Prove using strongest postcondition { x=a  y=b } t := x { x=a  y=b  t=a } x := y y := t { x=b  y=a }

Prove using strongest postcondition { x=a  y=b } t := x { x=a  y=b  t=a } x := y { x=b  y=b  t=a } y := t { x=b  y=a }

Prove using strongest postcondition { x=a  y=b } t := x { x=a  y=b  t=a } x := y { x=b  y=b  t=a } y := t { x=b  y=a  t=a } { x=b  y=a } // cons

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| }

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| }

{ x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Sum program – specify { x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Define Sum(0, n) = 0+1+…+n { ? } x := 0 res := 0 while (x<y) do x := x+1 res := res+x { ? } Background axiom

{ x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Sum program – specify { x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Define Sum(0, n) = 0+1+…+n { y0 } x := 0 res := 0 while (x<y) do x := x+1 res := res+x { res = Sum(0, y) } Background axiom

{ x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Sum program – prove { x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Define Sum(0, n) = 0+1+…+n { y0 } x := 0 res := 0 Inv = while (x<y) do x := x+1 res := res+x { res = Sum(0, y) }

{ x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Sum program – prove { x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Define Sum(0, n) = 0+1+…+n { y0 } x := 0 { y0  x=0 } res := 0 Inv = while (x<y) do x := x+1 res := res+x { res = Sum(0, y) }

{ x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Sum program – prove { x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Define Sum(0, n) = 0+1+…+n { y0 } x := 0 { y0  x=0 } res := 0 { y0  x=0  res=0 } Inv = while (x<y) do x := x+1 res := res+x { res = Sum(0, y) }

{ x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Sum program – prove { x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } 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)  xy } while (x<y) do x := x+1 res := res+x { res = Sum(0, y) }

{ x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Sum program – prove { x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } 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)  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 res := res+x { res = Sum(0, y) }

{ x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Sum program – prove { x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } 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)  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 { res = Sum(0, y) }

{ x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Sum program – prove { x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } 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)  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 { res = Sum(0, y) }

{ x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Sum program – prove { x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } 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)  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) }

{ x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } Buggy sum program 1 { x=Sum(0, n) } { y=n+1 } { x+y=Sum(0, n+1) } 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)  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) }

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)  x>y }  {res = Sum(0, y) }

Handling data structures

Problems with Hoare logic and heaps { P[a/x] } x := a { P } Consider the annotated program { y=5 } y := 5; { y=5 } x := &y; { y=5 } *x := 7; { y=5 } Is it correct? The rule works on a syntactic level unaware of possible aliasing between different terms (y and *x in our case)

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?

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

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 Employed by Dafny

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,  

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) }

Array update rules (wlp) S ::= x := a | x := y[a] | y[a] := x | skip | S1; S2 | if b then S1 else S2 | while b do S A very general approach – allows handling many data types 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 }

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}

Array update rules (sp) { P } x := y[a] { v. x=y(a[v/x])  P[v/x] } [array-loadF] { y=g  P } y[a1] := a2 { y=g[a1[g/y]a2[g/y]] } [array-updateF]

Small array update rules (sp) [array-loadF] { y=g  a=b } x := y[a] { x=g(b) } In both rules v, g, and b are fresh [array-updateF] { x=v  y=g  a=b } y[a] := x { y=g[bv] }

practice proving programs with arrays

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 { x=N } { m. (m0  m<N)  nums(m)res } { m. m0  m<N  nums(m)=res } { nums=orig_nums }

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 }

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  nums=orig_nums} C {x=N  nums=orig_nums} We can refer to assertions from earlier proofs in writing new proofs

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 res := nums[x] { x=k  k<N } x := x + 1 { x=k+1  k<N } { xN  xN } { x=N } Use frame rule

Array-max example: Post2 nums : array N : int // N stands for num’s length { nums=orig_nums } x := 0 res := nums[0] while x < N if nums[x] > res then res := nums[x] { nums=orig_nums } Use frame rule

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)  (res≥nums(x)  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x-1  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 }

Proving termination By Noble0 (Own work) [CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons

Total correctness semantics for While [ P[a/x] ] x := a [ P ] [assp] [ P ] skip [ P ] [skipp] [ P ] S1 [ Q ], [ Q ] S2 [ R ] [ P ] S1; S2 [ R ] [compp] [ b  P ] S1 [ Q ], [ b  P ] S2 [ Q ] [ P ] if b then S1 else S2 [ Q ] [ifp] [whilep] [ P(z+1) ] S [ P(z) ] [ z. P(z) ] while b do S [ P(0) ] P(z+1)  b P(0)  b [ P’ ] S [ Q’ ] [ P ] S [ Q ] [consp] if PP’ and Q’Q

Total correctness semantics for While [ P[a/x] ] x := a [ P ] [assp] [ P ] skip [ P ] [skipp] [ P ] S1 [ Q ], [ Q ] S2 [ R ] [ P ] S1; S2 [ R ] [compp] [ b  P ] S1 [ Q ], [ b  P ] S2 [ Q ] [ P ] if b then S1 else S2 [ Q ] [ifp] Rank, or Loop variant [whilep] [ b  P  t=k ] S [ P  t<k ] [ P ] while b do S [ b  P ] P  t0 [ P’ ] S [ Q’ ] [ P ] S [ Q ] [consp] if PP’ and Q’Q

Proving termination There is a more general rule based on well-founded 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 [ ]

Proving termination There is a more general rule based on well-founded 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 ]

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 [ ? ]

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 ]

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 ]

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 := x + 1 // [ N-x<k  N-x0 ] [ true ] Capture initial value of x, since it changes in the loop

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 ]

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 ]

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 ]

Zune calendar bug while (days > 365) { if (IsLeapYear(year)) { if (days > 366) { days -= 366; year += 1; } } else { days -= 365;

Fixed code while (days > 365) { if (IsLeapYear(year)) { if (days > 366) { days -= 366; year += 1; } else { break; } else { days -= 365;

Fixed code – specify termination [ ? ] while (days > 365) { if (IsLeapYear(year)) { if (days > 366) { days -= 366; year += 1; } else { break; } else { days -= 365;

Fixed code – specify variant [ true ] Variant = [ ? ] while (days > 365) { if (IsLeapYear(year)) { if (days > 366) { days -= 366; year += 1; } else { break; } else { days -= 365; [ ? ]

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; // [ days0  days<k ] Let’s model break by a small cheat – assume execution never gets past it

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; } else { [ k=days  days>365  days366 ] break; [ false ] [ (days=k-366  days>0)  false ] -> [ days<k  days>0 ] } else { days -= 365; [ k-365=days  days-365>365 ] -> [ k-365=days  days0 ] -> [ days<k  days0 ] [ days<k  days0 ]

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 { b  P } S { b } { P } while b do S { false } [while-ntp]

conclusion

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

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

See you next time