Spring 2017 Program Analysis and Verification Lecture 7: Axiomatic Semantics V Termination Roman Manevich Ben-Gurion University
Tentative syllabus Program Verification Program Analysis Basics Operational semantics Hoare Logic Predicate Calculus Data Structures Termination 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 Extending Hoare logic to handle data structures
Proving termination Agenda 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] Rank, or Loop variant [ b P ] S1 [ Q ], [ b P ] S2 [ Q ] [ P ] if b then S1 else S2 [ Q ] [ifp] [whilep] [ b P t=k ] S [ P t<k ] [ P ] while b do S [ b P ] P t0 [ P’ ] S [ Q’ ] [ P ] S [ Q ] [consp] if PP’ 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-x0 ] if nums[x] > res then res := nums[x] x := x + 1 // [ N-x<k N-x0 ] [ 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-x00 ] if nums[x] > res then res := nums[x] x := x + 1 // [ N-x<k N-x0 ] [ 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-x00 ] if nums[x] > res then res := nums[x] [ x=x0 x0<N N-x0=k N-x00 ] // Frame x := x + 1 // [ N-x<k N-x0 ] [ 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-x00 ] if nums[x] > res then res := nums[x] [ x=x0 x0<N N-x0=k N-x00 ] // Frame x := x + 1 [ x=x0+1 x0<N N-x0=k N-x00 ] // [ N-x<k N-x0 ] [ 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-x00 ] if nums[x] > res then res := nums[x] [ x=x0 x0<N N-x0=k N-x00 ] // Frame x := x + 1 [ x=x0+1 x0<N N-x0=k N-x00 ] [ N-x<k N-x0 ] // 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 days0 ] if (IsLeapYear(year)) { if (days > 366) { days -= 366; year += 1; } else { break; [ false ] } else { days -= 365; // [ days0 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) { [ days0 k=days days>365 ] -> [ days0 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 days366 ] break; [ false ] [ (days=k-366 days>0) false ] -> [ days<k days>0 ] } else { days -= 365; [ k-365=days days-365>365 ] -> [ k-365=days days0 ] -> [ days<k days0 ] [ days<k days0 ]
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 } { P } while b do S { false } [while-ntp]
practice
Two counters: find precondition [ ] b := 0; Var = [ ] while (x0 y0) do b := 1−b; if (b) x := x−1 else y := y−1 [ true ]
Two counters: find variant [ x>0 y>0 ] b := 0; Var = [ ] while (x0 y0) do b := 1−b; if (b) x := x−1 else y := y−1 [ true ]
Two counters: find variant [ x>0 y>0 ] b := 0; Var = [ t=x+y ] while (x0 y0) do b := 1−b; if (b) x := x−1 else y := y−1 [ true ]
Slow countdown: Find variant [ true ] flag := 0; Variant = [ ] while (x>0) do flag := 1−flag; if flag=0 then x := x−1 [ true ]
Automating termination Many tools focus on finding ranking functions as linear combination of the variables Lexicographic ranking functions are sometimes needed State-of-the-art approaches are modular – find a rank function per path and use sophisticated theory to construct a disjunctive termination argument
Working with Dafny
Installing Dafny See this link Install Visual Studio Download and install Boogie Download and install Dafny Follow interactive tutorial Youtube channel: Verification Corner
Elements method : compilable code function : a mathematical function, defined as an expression (side effect-free), possibly containing recursion You may need to supply a decreases expression to prove that it is well-defined predicate : a Boolean-valued function Useful for writing assertions lemma/ghost method : a code-less method assume : determines that an assertion holds assert : a proof obligation Useful for debugging proof attempts decreases clause : a loop variant
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 enjoy the vacation
Termination of angle search Prove that the following program always terminates if y0 y<360 then while (xy) do x := x+1; if x360 then x := 0
Termination of angle search { } if y0 y<360 then { } variant = { } while (xy) do { } x := x+1; { } if x360 then { } x := 0 { } { }