# Model-based reasoning meets code verification Michael Butler 21 May 2014 WG 2.3 Meeting 55, Orlando.

## Presentation on theme: "Model-based reasoning meets code verification Michael Butler 21 May 2014 WG 2.3 Meeting 55, Orlando."— Presentation transcript:

Model-based reasoning meets code verification Michael Butler 21 May 2014 WG 2.3 Meeting 55, Orlando

Talk is about Distinguish algorithm from its implementation Use of patterns / ghost elements for – Verification of algorithm wrt its spec independently from its implementation – Verification of implementation wrt algorithm – Mechanised verification by linking existing verification systems Dafny & Event-B/Rodin

Model of a transition system SETS STATE CONSTANTS init, tr, inv, reach tr ∈ STATE ↔ STATE// transition relation inv ⊆ STATE // states satisfying invariant init ⊆ inv// initial states (satisfy inv) reach = tr * [init]// set of reachable states

Algorithm Specification IF reach ⊆ inv THEN result := SAFE ELSE result := UNSAFE END

Representing the transition system in Dafny class STATE {}; method initStates returns ( res: seq ) ensures res == initial states of system; method get_successors( s:STATE ) returns ( succ: seq ) ensures succ == “all successors of s” method check_inv(s: STATE) returns ( ok:bool ) ensures ok == “s satisfies invariant”

Implementation of algorithm method CheckReach() returns ( pass: bool ) {var safe : seq := initStates() ; var err: seq := [] ; var i := 0 ; while ( i < |safe| && err == [] ) { var j := 0; s1 := safe[i]; succ := get_successors(s1); while ( j < |succ| && err == [] ) { var s2 := succ[j]; if ( s2 !in safe && s2 !in err ) { if ( check_inv(s2) ) {safe := safe + [s2]; } else { err := err + [s2]; }} ; j := j + 1; } ; i := i + 1; } ; if ( err == [] ) { pass := true; }else{ pass := false; } }

FindOk NoFind Search StartFind Pass(i) FindOk some i StartFind Fail(i) NoFind all i Search algorithm pattern FindOk: ∃x∈S P(x) or NoFind: ∀x∈S ¬P(x) 7 xor

Could merge to form a (less abstract) sequential algorithm StartFind ; for i in S do Fail(i) [] Pass(i) ; exit od ; if exit then FindOk else NoFind fi 8

FindOk StartFind Pass(p,i) FindOk some i:S[p] Alternatively refine to parallel model Partition S so that search is farmed out to multiple processors p ∈ P This is a simple refinement step in Event-B some p:P 9

What’s in a refinement pattern? Determining the refined events is relatively easy once we decide on the appropriate abstract program structure to use But determining the right gluing invariants can be difficult Patterns: from a certain specification structure – determine refined events – gluing invariants – convergence variants 10

“All Condition” Pattern CondAll ≙ when ∀ i ∈ S Cond(i) then action end 11 Search Fail: Cond(i) ≙ ¬Property(i)

Refinement of CondAll Step ≙ any i where Cond(i) ∧ s ∉ oStep then oStep := oStep ∪ {i} end CondAll ≙ when oStep = S then action end 12 CondAll Step(i) CondAll all i:S invariant ∀ i ∈ oStep Cond(i) i ∈ oStep iff Step(i) event has occurred

“Some Condition” Pattern CondSome ≙ when ∃ i. i ∈ S ∧ Cond(i) then action end CondSome ≙ any i where i ∈ S Cond(i) then action(i) end 13

Refinement of CondSome Step ≙ any i where Cond(i) ∧ s ∉ oStep then oStep := oStep ∪ {i} end CondSome ≙ any i where i ∈ oStep then action(i) end 14 CondSome Step(i) CondSome some i:S invariant ∀ i ∈ oStep Cond(i)

FindOk NoFind Search StartFind Pass(i) FindOk some i StartFind Fail(i) NoFind all i Refinement invariants for search Invariant:o Pass ⊆ S∩P Invariant:o Fail ⊆ S \ P 15 xor

FindOk NoFind Search StartFind Pass(i) FindOk some i StartFind Fail(i) NoFind all i Convergence variant for search Variant: S \ ( oPass ∪ oFail ) Invariant:finite(S) 16 xor

Event-B spec of reachability Pass ≙ WHEN reach ⊆ inv THEN result := SAFE END Fail ≙ ANY e WHERE e ∈ reach e ∉ inv THEN result := UNSAFE error_state := e END reach is a ghost constant and it needs to be removed in the implementation Refine the model to one that computes the reachable states step- by-step

Fail Pass Reach Start Error(s) Fail Some s Start Ok(s) Pass All s Guards for reachability events Fail: ∃s∈reach ¬Inv(s) or Pass: ∀s∈reach Inv(s) 18 xor

Fail Pass Reach Start Error(s) Fail Some s Start Safe(s) Pass All s Invariants for reachability refinement Invariant:oSafe ⊆ reach ∩ inv Invariant:o Error ⊆ reach \ inv 19 xor

Spec of Safe event EventSafe // add a new successor state that satisfies invariant to oSafe ANY s WHERE s ∈ reach s ∈ inv s ∉ oSafe THEN oSafe := oSafe ∪ {s} END

Convergence of Safe and Error events Variant: S \ ( oSafe ∪ oFail ) Invariant:finite(S)

Refining the Fail event Abstract Fail ≙ ANY e WHERE e ∈ reach e ∉ inv THEN result := FAIL error_state := e END Refined Fail ≙ ANY e WHERE e ∈ oError THEN result := FAIL error_state := e END Invariant: oError ⊆ reach ∖ inv Prove guard strengthening refined guard = e ∈ oError ⇒ “invariant” e ∈ reach ∖ inv = abstract guard

Refining the Pass event Abstract Pass ≙ WHEN reach ⊆ inv THEN result := OK END Refined Pass ≙ WHEN oSafe = reach THEN result := OK END Invariant: oSafe ⊆ reach ∩ inv Prove guard strengthening oSafe = reach ⇒ “invariant” reach ⊆ reach ∩ inv ⇒ “set theory” reach ⊆ inv

The specter of reach remains Fail events do not refer to reach so no further refinement required Pass events still do refer to reach, so further refinement required Refine the guard of the Safe(s) event: s ∈ reach ⇐ “reach is a fixed point” ∃ s1 s1 ∈ reach ∧ s1 ↦ s ∈ tr ⇐ “oSafe ⊆ reach” ∃ s1 s1 ∈ oSafe ∧ s1 ↦ s ∈ tr

Add new parameter to Safe event Event Safe ANY s, s1 WHERE s1 ∈ oSafe s1 ↦ s ∈ tr s ∈ inv s ∉ oSafe THEN oSafe := oSafe ∪ {s} END

Extra parameter gives nested iteration 26 Pass Safe(s) Pass all s Pass Safe(s1,s) Pass all s1 all s

Further refinement: tracking the explored states A state is explored if it is in safe and all its successors are reached Invariant: tr[ explored ] ⊆ ( oSafe ∪ oError ) Introduce new event: Event Mark_explored ANY s WHERE s ∈ rac s ∉ explored tr[{s}] ⊆ ( oSafe ∪ oError ) THEN explored := explored ∪ {s} END

Refining the Pass event Pass ≙ WHEN oSafe = reach THEN result := OK END Refined Pass ≙ WHEN explored = oSafe oError = {} THEN result := OK END Invariant: tr[ explored ] ⊆ ( oSafe ∪ oError ) Prove guard strengthening explored = oSafe ∧ oError = {} ⇒ “invariant” tr[ oSafe ] ⊆ oSafe ⇒ “reach is least fixed point” reach ⊆ oSafe

What to verify in Dafny? Verify that the Dafny code is a correct refinement of the final Event-B model Event-B variables become ghost variables in Dafny Gluing invariants in Dafny: invariant oSafe == seqElems(safe); invariant oError == seqElems(err); invariant explored == seqElems(safe[0..i]); Embed the events into the Dafny code

Embed events in the Dafny method CheckReach() returns ( pass: bool ) {… Init while ( i < |safe| && err == [] ) { var j := 0; s1 := safe[i]; succ := get_successors(s1); while ( j < |succ| && err == [] ) { var s2 := succ[j]; if ( s2 !in safe && s2 !in err ) { if ( check_inv(s2) ) {safe := safe + [s2]; Safe(s1,s2); }; else { err := err + [s2]; Error(s2); }} ; j := j + 1; } ; Mark_Explored ; i := i + 1; } ; if ( err == [] ) { pass := true; Pass ; } else{ pass := false; Fail ; } }

Ghost busters Guarded event: when G then A end == (assume G) ; A Eliminating guards with assertions (assert G) ; (assume G) ; A ⊑ A Once guards are removed, ghost variables no longer influence the program so can be eliminated

Concluding Correctness of algorithm is proved independently of Dafny (with help from patterns) At Dafny level we prove that the code is a correct implementation of the algorithm – Avoided any duplication in proof except for Dafny variants NB: proposed “embeddding” method for proving Dafny refines the algorithm only works if code is deterministic

Download ppt "Model-based reasoning meets code verification Michael Butler 21 May 2014 WG 2.3 Meeting 55, Orlando."

Similar presentations