header {* \isaheader{Verification Condition Generator} *} theory VCG = AbsSem: text {* For technical reasons Isabelle's locales do not (yet?) support recursive definitions. Hence, we define the VCG outside and refer to this defintion inside the locale VCG, which we define below. This external definition looks quite ugly as a rat tail of parameters is in the signature. The definition as it shoul be is derived as lemma {\bf vcgdef} below. *} section {* Inductive Safety Formulas *} (*<*) lemma filterreduction: "i mem (S:: 'a list) \ (length [a\S . a\i] < length S)" apply (induct S) apply simp apply (case_tac "i=a") apply (rule impI) apply auto apply (subgoal_tac "\ a\set S. a \ i") apply (simp add: set_mem_eq) apply (simp add: set_mem_eq) apply auto done (*>*) consts isafe:: "('pos list \ 'program \ ('pos \ 'form option) \ 'pos \ 'form \ ('form list \ 'form) \ ('form \ 'form \ 'form) \ ( 'program \ 'pos \ 'form) \ ( 'program \ 'pos \ ('pos \ 'form) list) \ ( 'program \ 'pos \ 'pos \ 'form \ 'form)) \ 'form" recdef isafe "measure (\ a. length (fst a))" "isafe (S,prg,anF,pc,FalseF',Conj',Impl',appF',succsF',wpF') = (if \ (pc mem S) then FalseF' else Conj' ([appF' prg pc] @ (case (anF pc) of None \ (map (\ (pc',B). Impl' B (wpF' prg pc pc' (isafe ((filter (\ a. a \ pc) S), prg, anF, pc', FalseF', Conj', Impl', appF', succsF', wpF') ) ) ) (succsF' prg pc)) | Some a \ [a])))" (hints recdef_simp: filterreduction) section {* External VCG *} text {* The vcG functions takes the auxiliary functions from the framework as additional arguments *} consts vcG:: "('form list \ 'form) \ ('form \ 'form \ 'form) \ 'form \ ('program \ 'pos) \ ('program \ 'form) \ ('program \ 'pos \ 'form) \ ('program \ 'pos \ ('pos \ 'form) list) \ ('program \ 'pos \ 'pos \ 'form \ 'form) \ ('program \ 'pos list) \ ('program \ 'pos list) \ ('program \ ('pos \ 'form option)) \ 'program \ 'form" defs vcG_def: "vcG Conj Impl FalseF ipc initF safeF succsF wpF domC domA an p \ (let an' = (\ i. isafe(domC p,p,an p,i,FalseF,Conj,Impl,safeF,succsF,wpF)) in (Conj ((Impl (initF p) (an' (ipc p)))#(map (\ i. Conj (map (\ (j,B). Impl (Conj [ (an' i), B]) ((wpF p i j) (an' j))) (succsF p i))) (domA p)))))" section {* Pre Safe States *} text {* Here we define the set of pre safe states. These are all initial states and states that are reachable from those by only traversing inductively safe intermediate states *} section {* Generic Verification Conditons *} locale VCG = AbsSem + fixes vcg:: " 'prog \ 'form" defines "vcg \ \ \. vcG Conj Impl FalseF ipc initF safeF succsF wpF domC domA anF \" fixes isafe'::"('pos list \ 'prog \ 'pos) \ 'form" defines "isafe' \ \ (S,\,pc). isafe(S,\,(anF \),pc,FalseF,Conj,Impl,safeF,succsF,wpF)" fixes isafeF::" 'prog \ 'pos \ 'form" defines "isafeF \ (\ \ pc. isafe' (domC \,\,pc))" (*<*) theorem (in VCG) isafe'_simps: "isafe' (S,\,pc) = (if \ (pc mem S) then FalseF else Conj ([safeF \ pc]@ (case (anF \ pc) of None \ (map (\ (pc',B). (Impl B ((wpF \ pc pc') (isafe' ((filter (\ a. a \ pc) S),\,pc')))) ) (succsF \ pc)) | Some a \ [a])))" apply (unfold isafe'_def) apply simp apply (rule impI) apply (simp only: split_def) apply (simp only: fst_conv) apply (simp only: snd_conv) apply (simp only: fst_conv) done (*>*) (*<*) lemma (in VCG) isafe'induct: assumes IH: "\S \ pc. \ pc' B. (pc',B) \ set (succsF \ pc) \ (anF \ pc) = None \ (pc mem S) \ P [a\S. a\pc] \ pc' \ P S \ pc" shows "P (u\'pos list) (v\'prog) (x\'pos)" proof - have "(anF v) = (anF v) \ succsF = succsF \ P (u\'pos list) (v::'prog) (x\'pos)" apply (rule_tac P = "\S \ pan pc FalseF' Conj' Impl' safeF' succsF' wpF'. (pan = (anF \)) \ succsF' = succsF \ P (S\'pos list) (\\'prog) (pc\'pos)" in isafe.induct) apply (rule impI)+ apply (rule IH) apply simp done thus ?thesis by simp qed (*>*) (*<*) lemma (in VCG) isafe'_red: "(wf \) \ (\ pc. \ B. (anF \ pc) = None \ (noAnnOnWay succsF anF \ pc pc') \ isafe'([x\l. x\pc],\,pc') = isafe'(l,\,pc'))" apply (rule_tac P="\ u v x. (wf v) \(\ pc. \ B. (anF v pc) = None \ (noAnnOnWay succsF anF v pc x) \ isafe'([x\u. x\pc],v,x) = isafe'(u,v,x))" and u="l" and v="\" and x="pc'" in isafe'induct) apply (rule allI | rule impI)+ apply (rule_tac P="\ x. isafe' ([x \ S. x \ pca],\,pc) = x" in ssubst[OF isafe'_simps]) apply (rule_tac P="\ x. x = (if \ pc mem S then \ else \([safeF \ pc] @ (case anF \ pc of None \ map (\(pc', B). B \ wpF \ pc pc' (isafe' ([a\S . a \ pc], \, pc'))) (succsF \ pc) | Some a \ [a])))" in ssubst[OF isafe'_simps]) apply (subgoal_tac "pc \ pca") apply (case_tac "\ (pc mem S)") apply (simp only: split_if set_mem_eq) apply (rule conjI) prefer 2 apply (rule impI) apply clarify apply (rule impI) apply (frule_tac pc'="pc" and l="S" and pc="pca" in notin_simp) apply (simp only:split_if) apply simp apply (simp only:split_if) apply (rule conjI) apply (rule impI) apply clarify apply (rule impI) apply (frule not_sym) apply (simp only: set_mem_eq) apply (frule_tac pc'="pc" and l="S" and pc="pca" in neg_notin_simp) apply assumption apply (simp only:split_if) apply simp apply (case_tac "(anF \ pc) = None") prefer 2 apply (drule option_case_simp) apply (erule exE) apply (simp del:isafe'_simps) apply (simp (no_asm_simp) del:isafe'_simps) apply (rule ConjEq) apply (simp only: ListEq) apply (rule conjI) apply simp apply (rule map_simp) apply simp apply (rule allI) apply (simp only: split_paired_all) apply (rename_tac "S" "\" "pc" "pca" "pc'a" "Ba") apply (rule impI) apply (simp (no_asm_simp) del:isafe'_simps) apply (rule ImplEq) apply simp apply (rule_tac f="(wpF \ pc pc'a)" in arg_cong) apply (case_tac "pca \ set S") prefer 2 apply (rule_tac f="isafe'" in arg_cong) apply simp apply (rule_tac pc="pca" and l="S" and pc'="pc" in filter_list_simp) apply assumption apply (erule_tac x="pc'a" in allE) apply (subgoal_tac "None = None") prefer 2 apply simp apply (erule impE) apply simp apply (erule_tac x="Ba" in exI) apply (erule_tac x="pca" in allE) apply (drule mp, assumption)+ apply (subgoal_tac "noAnnOnWay succsF anF \ pca pc'a") prefer 2 apply (simp only:noAnnOnWay_def) apply (erule exE) apply (rule_tac x="l@[pc]" in exI) apply (rule conjI) apply (erule conjE) apply (frule_tac l="(pca#l)" and p="pc" and sc="succsF \" and p'="pc'a" and B="Ba" in paths.step) apply assumption apply simp apply (simp only:noAnn_def) apply (rule allI) apply (rule impI) apply (subgoal_tac "p \ set (pca#l) \ p=pc") prefer 2 apply simp apply (simp only:disj_commute) apply (case_tac "p = pc") apply simp apply simp apply (case_tac "p = pca") apply simp apply simp apply (drule mp, assumption) apply (drule_tac t="isafe' ?P" in sym) apply simp apply (rule_tac f="isafe'" in arg_cong) apply simp apply (rule_tac f="\ P. filter P S " in arg_cong) apply (rule ext) apply blast apply (case_tac "pc = pca") apply (simp only:noAnnOnWay_def) apply (erule exE) apply (subgoal_tac "isCycle succsF \ ((pca # l) @ [pca])") apply (drule wf_anF) apply (unfold enoughAn_def) apply (erule_tac x="(pca#l)@[pca]" in allE) apply (drule mp) apply assumption apply (erule conjE) apply (drule_tac l="(pca#l)" and p="pca" in noAnn_ext) apply assumption apply clarify apply (simp only:simp_thms) apply (erule conjE) apply (unfold isCycle_def) apply (rule conjI) apply assumption apply simp apply assumption done (*>*) (*<*) lemma (in VCG) isafeF_no_annotation: "\ wf \; (anF \ pc) = None; pc\ set (domC \) \ \ (isafeF \ pc) = Conj ([safeF \ pc]@ (map (\ (pc',B). (Impl B ((wpF \ pc pc') (isafeF \ pc')))) (succsF \ pc) ) )" --{* This lemma proves that in sufficiently annotated programs (wf p pan) a function call isafe(domL p, pan, pc, ) never reaches address pc twice. It terminates without the artificial break implemented by feeding in (domL p). *} apply (subgoal_tac "enoughAn succsF \ anF") prefer 2 apply (drule wf_anF) apply assumption apply (unfold isafeF_def) apply (simplesubst isafe'_simps) apply (simp del:isafe'_simps add: set_mem_eq) apply (rule ConjEq) apply (simp only:ListEq) apply (rule conjI) apply simp apply (rule map_simp) apply simp apply (rule allI) apply (simp only: split_paired_all) apply (rename_tac "pc''" "B") apply (rule impI) apply (simp only:split_def) apply (rule ImplEq) apply simp apply (simp del:isafe'_simps) apply (rule_tac f="(wpF \ pc pc'')" in arg_cong) apply (erule_tac \1="\" and l1="domC \" and pc'1="pc''" in isafe'_red[THEN impE]) apply (erule_tac x="pc" in allE) apply (erule_tac x="B'" in allE) apply (drule_tac P="(anF \ pc) = None" in mp) apply assumption apply (subgoal_tac "noAnnOnWay succsF anF \ pc pc''") apply (drule_tac P="noAnnOnWay succsF anF \ pc pc''" in mp) apply assumption apply assumption apply (erule_tac V="noAnnOnWay succsF anF \ pc pc'' \ ?P" in thin_rl) apply (unfold noAnnOnWay_def) apply (rule_tac x="[]" in exI) apply (rule conjI) apply simp apply (rule_tac p'="pc''" and B="B" and p="pc" and sc="succsF \" in paths.start) apply assumption apply (unfold noAnn_def) apply (rule allI) apply (rule impI) apply simp done (*>*) (*<*) lemma (in VCG) isafeFdef: "\ wf \ \ \ (isafeF \ pc) = (if (pc \ set (domC \)) then Conj ([safeF \ pc] @ (case (anF \ pc) of None \ (map (\ (pc',B). (Impl B ((wpF \ pc pc') (isafeF \ pc')))) (succsF \ pc)) | Some an \ [an])) else FalseF )" apply (case_tac "pc\ set (domC \)") apply (simp only: if_True) apply (case_tac "anF \ pc") apply (simp only: if_True option.cases) apply (drule_tac \="\" and pc="pc" in isafeF_no_annotation, assumption+) apply (simp only: option.cases) apply (simp add: isafeF_def isafe'_def set_mem_eq ) apply (simp add: isafeF_def isafe'_def set_mem_eq ) done (*>*) text {* This lemma shows that vcg could be defined as follows, if the locale mechanism allowed us recursive definitions *} lemma (in VCG) vcgdef: "\ wf \ \ \ vcg \ = Conj ((Impl (initF \) (isafeF \ (ipc \)))#(map (\ pc. Conj (map (\ (pc',B). Impl (Conj [ (isafeF \ pc), B]) ((wpF \ pc pc') (isafeF \ pc'))) (succsF \ pc))) (domA \))) " (*<*) apply (simp only: vcg_def vcG_def Let_def isafeF_def isafe'_def) apply simp done (*>*) end