Download presentation
Presentation is loading. Please wait.
Published byIgnacio Truitt Modified over 9 years ago
1
Model-based reasoning meets code verification Michael Butler 21 May 2014 WG 2.3 Meeting 55, Orlando
2
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
3
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
4
Algorithm Specification IF reach ⊆ inv THEN result := SAFE ELSE result := UNSAFE END
5
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”
6
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; } }
7
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
8
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
9
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
10
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
11
“All Condition” Pattern CondAll ≙ when ∀ i ∈ S Cond(i) then action end 11 Search Fail: Cond(i) ≙ ¬Property(i)
12
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
13
“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
14
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)
15
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
16
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
17
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
18
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
19
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
20
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
21
Convergence of Safe and Error events Variant: S \ ( oSafe ∪ oFail ) Invariant:finite(S)
22
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
23
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
24
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
25
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
26
Extra parameter gives nested iteration 26 Pass Safe(s) Pass all s Pass Safe(s1,s) Pass all s1 all s
27
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
28
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
29
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
30
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 ; } }
31
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
32
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
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.