Up to index of Isabelle/HOL/JinjaThreads
theory BVNoTypeError(* Title: JinjaThreads/BV/BVNoTypeError.thy Author: Gerwin Klein, Andreas Lochbihler *) header {* \isaheader{Welltyped Programs produce no Type Errors} *} theory BVNoTypeError imports "../JVM/JVMDefensive" BVSpecTypeSafe begin declare is_IntgI[intro, simp] declare is_BoolI[intro, simp] declare is_RefI [simp] declare defs1 [simp del] lemma wt_jvm_prog_states: "[| wf_jvm_progΦ P; P \<turnstile> C sees M: Ts->T = (mxs, mxl, ins, et) in C; Φ C M ! pc = τ; pc < size ins |] ==> OK τ ∈ states P mxs (1+size Ts+mxl)" (*<*) apply (unfold wf_jvm_prog_phi_def) apply (drule (1) sees_wf_mdecl) apply (simp add: wf_mdecl_def wt_method_def check_types_def) apply (blast intro: nth_in) done (*>*) text {* The main theorem: welltyped programs do not produce type errors if they are started in a conformant state. *} theorem no_type_error: fixes σ :: jvm_state assumes welltyped: "wf_jvm_progΦ P" and conforms: "P,Φ \<turnstile> σ \<surd>" shows "exec_d P σ ≠ TypeError" (*<*) proof - from welltyped obtain mb where wf: "wf_prog mb P" by (fast dest: wt_jvm_progD) obtain xcp h frs where s [simp]: "σ = (xcp, h, frs)" by (cases σ) have "check P σ" proof(cases frs) case Nil with conforms show ?thesis by (unfold correct_state_def check_def) auto next case (Cons f frs') then obtain stk reg C M pc where frs [simp]: "frs = (stk,reg,C,M,pc)#frs'" and f: "f = (stk,reg,C,M,pc)" by(cases f) fastsimp from conforms obtain ST LT Ts T mxs mxl ins xt where hconf: "P \<turnstile> h \<surd>" and meth: "P \<turnstile> C sees M:Ts->T = (mxs, mxl, ins, xt) in C" and Φ: "Φ C M ! pc = Some (ST,LT)" and frame: "conf_f P h (ST,LT) ins (stk,reg,C,M,pc)" and frames: "conf_fs P h Φ M (size Ts) T frs'" by (fastsimp simp add: correct_state_def dest: sees_method_fun) from frame obtain stk: "P,h \<turnstile> stk [:≤] ST" and reg: "P,h \<turnstile> reg [:≤\<top>] LT" and pc: "pc < size ins" by (simp add: conf_f_def) from welltyped meth Φ pc have "OK (Some (ST, LT)) ∈ states P mxs (1+size Ts+mxl)" by (rule wt_jvm_prog_states) hence "size ST ≤ mxs" by (auto simp add: JVM_states_unfold) with stk have mxs: "size stk ≤ mxs" by (auto dest: list_all2_lengthD) from welltyped meth pc have "P,T,mxs,size ins,xt \<turnstile> ins!pc,pc :: Φ C M" by (rule wt_jvm_prog_impl_wt_instr) hence app0: "app (ins!pc) P mxs T pc (size ins) xt (Φ C M!pc) " by (simp add: wt_instr_def) with Φ have eff: "∀(pc',s')∈set (eff (ins ! pc) P pc xt (Φ C M ! pc)). pc' < size ins" by (unfold app_def) simp from app0 Φ have app: "xcpt_app (ins!pc) P pc mxs xt (ST,LT) ∧ appi (ins!pc, P, pc, mxs, T, (ST,LT))" by (clarsimp simp add: app_def) show ?thesis proof(cases xcp) case None note xcp[simp] = this from app eff stk reg have "check_instr (ins!pc) P h stk reg C M pc frs'" proof (cases "ins!pc") case ALoad with app stk reg Φ obtain T ST' where ST: "ST = Integer # T # ST'" and TNT: "T ≠ NT --> (∃T'. T = T'⌊⌉)" by auto from stk ST obtain i stk' ref where stk': "stk = Intg i # ref # stk'" and ref: "P,h \<turnstile> ref :≤ T" by(auto simp add: conf_def) from ref TNT have is_Ref: "is_Ref ref" by(auto) moreover { assume refN: "ref ≠ Null" with ref have "T ≠ NT" by auto with TNT obtain T' where T': "T = T'⌊⌉" by auto with ref refN is_Ref wf have "∃T el. h (the_Addr ref) = ⌊Arr T el⌋" by(auto simp add:conf_def widen_Array) } ultimately show ?thesis using ALoad stk' by(auto) next case AStore with app stk reg Φ obtain T U ST' where ST: "ST = T # Integer # U # ST'" and TNT: "U ≠ NT --> (∃T'. U = T'⌊⌉)" by auto from stk ST obtain e i stk' ref where stk': "stk = e # Intg i # ref # stk'" and ref: "P,h \<turnstile> ref :≤ U" and e: "P,h \<turnstile> e :≤ T" by(fastsimp simp add: conf_def) from ref TNT have is_Ref: "is_Ref ref" by(auto) moreover { assume refN: "ref ≠ Null" with ref have "U ≠ NT" by auto with TNT obtain T' where T': "U = T'⌊⌉" by auto with ref refN is_Ref wf have "∃T el. h (the_Addr ref) = ⌊Arr T el⌋" by(auto simp add:conf_def widen_Array) } ultimately show ?thesis using AStore stk' by(auto) next case ALength with app stk reg Φ obtain T ST' where ST: "ST = T # ST'" and TNT: "T ≠ NT --> (∃T'. T = T'⌊⌉)" by auto from stk ST obtain stk' ref where stk': "stk = ref # stk'" and ref: "P,h \<turnstile> ref :≤ T" by(auto simp add: conf_def) from ref TNT have is_Ref: "is_Ref ref" by(auto) moreover { assume refN: "ref ≠ Null" with ref have "T ≠ NT" by auto with TNT obtain T' where T': "T = T'⌊⌉" by auto with ref refN is_Ref wf have "∃T el. h (the_Addr ref) = ⌊Arr T el⌋" by(auto simp add:conf_def widen_Array) } ultimately show ?thesis using ALength stk' by(auto) next case (Getfield F C) with app stk reg Φ obtain v vT stk' where field: "P \<turnstile> C sees F:vT in C" and stk: "stk = v # stk'" and conf: "P,h \<turnstile> v :≤ Class C" by auto from field wf have CObject: "C ≠ Object" by(auto dest: wf_Object_field_empty has_fields_fun simp add: sees_field_def) from conf have is_Ref: "is_Ref v" by auto moreover { assume "v ≠ Null" with conf field is_Ref wf CObject have "∃D vs. h (the_Addr v) = Some (Obj D vs) ∧ P \<turnstile> D \<preceq>* C" by (auto dest!: non_npD) } ultimately show ?thesis using Getfield field stk hconf apply clarsimp apply (rule conjI, fastsimp) apply clarsimp apply (drule has_visible_field) apply (drule (1) has_field_mono) apply (drule (1) hconfD) apply (unfold oconf_def has_field_def) apply (fastsimp dest: has_fields_fun) done next case (Putfield F C) with app stk reg Φ obtain v ref vT stk' where field: "P \<turnstile> C sees F:vT in C" and stk: "stk = v # ref # stk'" and confv: "P,h \<turnstile> v :≤ vT" and confr: "P,h \<turnstile> ref :≤ Class C" by fastsimp from field wf have CObject: "C ≠ Object" by(auto dest: wf_Object_field_empty has_fields_fun simp add: sees_field_def) from confr have is_Ref: "is_Ref ref" by simp moreover { assume "ref ≠ Null" with confr field is_Ref wf CObject have "∃D vs. h (the_Addr ref) = Some (Obj D vs) ∧ P \<turnstile> D \<preceq>* C" by (auto dest: non_npD) } ultimately show ?thesis using Putfield field stk confv by fastsimp next case (Invoke M' n) with app have n: "n < size ST" by simp from stk have [simp]: "size stk = size ST" by (rule list_all2_lengthD) { assume "stk!n = Null" with n Invoke have ?thesis by simp } moreover { assume "ST!n = NT" with n stk have "stk!n = Null" by (auto simp: list_all2_conv_all_nth) with n Invoke have ?thesis by simp } moreover { assume Null: "stk!n ≠ Null" and NT: "ST!n ≠ NT" from NT app Invoke have "if is_external_call P (ST ! n) M' then ∃U. P \<turnstile> ST ! n•M'(rev (take n ST)) :: U else ∃D D' Ts T m. ST!n = Class D ∧ P \<turnstile> D sees M': Ts->T = m in D' ∧ P \<turnstile> rev (take n ST) [≤] Ts" by auto moreover { fix D D' Ts T m assume D: "ST!n = Class D" and M': "P \<turnstile> D sees M': Ts->T = m in D'" and Ts: "P \<turnstile> rev (take n ST) [≤] Ts" and nec: "¬ is_external_call P (ST ! n) M'" from M' wf have DObject: "D ≠ Object" by(auto dest: wf_Object_method_empty) from D stk n have "P,h \<turnstile> stk!n :≤ Class D" by (auto simp: list_all2_conv_all_nth) with Null DObject obtain a C' fs where [simp]: "stk!n = Addr a" "h a = Some (Obj C' fs)" and "P \<turnstile> C' \<preceq>* D" apply(auto dest!: conf_ClassD) by(case_tac obj, auto simp add: widen_Class) with `P \<turnstile> C' \<preceq>* D` wf M' obtain m' Ts' T' D'' where C': "P \<turnstile> C' sees M': Ts'->T' = m' in D''" and Ts': "P \<turnstile> Ts [≤] Ts'" by (auto dest!: sees_method_mono) from stk have "P,h \<turnstile> take n stk [:≤] take n ST" .. hence "P,h \<turnstile> rev (take n stk) [:≤] rev (take n ST)" .. also note Ts also note Ts' finally have "P,h \<turnstile> rev (take n stk) [:≤] Ts'" . moreover from C' have "¬ is_external_call P (Class C') M'" by(auto dest: external_call_not_sees_method[OF wf]) ultimately have ?thesis using Invoke Null n C' nec by (auto simp add: is_Ref_def2 has_methodI) } moreover { fix U assume iec: "is_external_call P (ST ! n) M'" and wtext: "P \<turnstile> ST ! n•M'(rev (take n ST)) :: U" from iec have "is_refT (ST ! n)" by(rule is_external_call_is_refT) moreover from stk n have "P,h \<turnstile> stk ! n :≤ ST ! n" by(rule list_all2_nthD2) ultimately obtain a ao where "stk ! n = Addr a" "h a = ⌊ao⌋" using Null by(auto simp add: conf_def elim!: is_refT.cases simp add: widen_Class widen_Array) moreover with `P,h \<turnstile> stk ! n :≤ ST ! n` obtain Ta where "P \<turnstile> Ta ≤ ST ! n" "typeofh (Addr a) = ⌊Ta⌋" "Ta ≠ NT" by(auto simp add: conf_def split: heapobj.split_asm) with wtext `P,h \<turnstile> stk ! n :≤ ST ! n` obtain U' where "P \<turnstile> Ta•M'(rev (take n ST)) :: U'" "P \<turnstile> U' ≤ U" by(auto intro: widens_refl dest: external_WTrt_widen_mono) with n have "is_external_call P Ta M'" by(auto dest: external_WT_is_external_call) moreover from stk have "P,h \<turnstile> take n stk [:≤] take n ST" by(rule list_all2_takeI) then obtain Us where "map typeofh (take n stk) = map Some Us" "P \<turnstile> Us [≤] take n ST" by(auto simp add: confs_conv_map) moreover hence "P \<turnstile> rev Us [≤] rev (take n ST)" by simp with `P \<turnstile> Ta•M'(rev (take n ST)) :: U'` `Ta ≠ NT` obtain U'' where "P \<turnstile> Ta•M'(rev Us) :: U''" by(auto dest: external_WTrt_widen_mono) moreover note Invoke Null n `stk ! n = Addr a` `typeofh (Addr a) = ⌊Ta⌋` ultimately have ?thesis by(force simp add: is_Ref_def rev_map[symmetric] split: heapobj.splits intro!: external_WT'.intros) } ultimately have ?thesis by(auto split: split_if_asm) } ultimately show ?thesis by blast next case Return with stk app Φ meth frames show ?thesis by (auto simp add: has_methodI) next case ThrowExc with stk app Φ meth frames show ?thesis by(fastsimp simp add: xcpt_app_def conf_def intro: widen_trans[OF _ widen_subcls]) next case (BinOpInstr bop) with stk app Φ meth frames show ?thesis by(auto simp add: conf_def)(force dest: WTrt_binop_widen_mono) qed (auto simp add: list_all2_lengthD) thus "check P σ" using meth pc mxs by (simp add: check_def has_methodI) next case (Some a) with meth pc mxs show ?thesis by(simp add: check_def has_methodI) qed qed thus "exec_d P σ ≠ TypeError" .. qed lemma welltyped_commute: "[|wf_jvm_progΦ P; P,Φ \<turnstile> σ \<surd>|] ==> P \<turnstile> Normal σ -ta-jvmd-> Normal σ' = P \<turnstile> σ -ta-jvm-> σ'" apply(rule iffI) apply(erule exec_1_d.cases, simp, fastsimp simp add: exec_d_def exec_1_iff split: split_if_asm) by(auto dest!: no_type_error intro!: exec_1_d.intros simp add: exec_d_def exec_1_iff split: split_if_asm) lemma BV_correct_d_1: "[| wf_jvm_progΦ P; P \<turnstile> Normal σ -ta-jvmd-> Normal σ'; P,Φ \<turnstile> σ \<surd> |] ==> P,Φ \<turnstile> σ' \<surd>" unfolding welltyped_commute by(rule BV_correct_1) text {* The theorem above tells us that, in welltyped programs, the defensive machine reaches the same result as the aggressive one (after arbitrarily many steps). *} theorem welltyped_aggressive_imp_defensive: "P \<turnstile> σ -tas-jvm->* σ' ==> wf_jvm_progΦ P ==> P,Φ \<turnstile> σ \<surd> ==> P \<turnstile> (Normal σ) -tas-jvmd->* (Normal σ')" apply(simp only: exec_star_def) apply(induct rule: rtrancl3p.induct) apply(simp add: exec_star_d_def) apply(simp) apply(simp only: exec_star_def[symmetric]) apply(frule BV_correct, assumption+) apply (drule_tac σ="a'" in no_type_error) apply(assumption) apply(drule no_type_error_commutes) apply (simp add: exec_star_d_def) apply(rule rtrancl3p_trans) apply(assumption) apply (drule exec_1_d_NormalI) apply(unfold exec_1_iff) apply(assumption) apply(rule rtrancl3p_step_converse) apply(assumption) apply(rule rtrancl3p_refl) done text {* As corollary we get that the aggressive and the defensive machine are equivalent for welltyped programs (if started in a conformant state or in the canonical start state) *} corollary welltyped_commutes: fixes σ :: jvm_state assumes wf: "wf_jvm_progΦ P" and conforms: "P,Φ \<turnstile> σ \<surd>" shows "P \<turnstile> (Normal σ) -tas-jvmd->* (Normal σ') = P \<turnstile> σ -tas-jvm->* σ'" apply (rule iffI) apply (erule defensive_imp_aggressive) apply (erule welltyped_aggressive_imp_defensive) apply (rule wf) apply (rule conforms) done corollary welltyped_initial_commutes: assumes wf: "wf_jvm_prog P" assumes meth: "P \<turnstile> C sees M:[]->T = b in C" defines start: "σ ≡ start_state P C M" shows "P \<turnstile> (Normal σ) -tas-jvmd->* (Normal σ') = P \<turnstile> σ -tas-jvm->* σ'" proof - from wf obtain Φ where wf': "wf_jvm_progΦ P" by (auto simp: wf_jvm_prog_def) from this meth have "P,Φ \<turnstile> σ \<surd>" unfolding start by (rule BV_correct_initial) with wf' show ?thesis by (rule welltyped_commutes) qed lemma not_TypeError_eq [iff]: "x ≠ TypeError = (∃t. x = Normal t)" by (cases x) auto locale cnf = fixes P and Φ and σ assumes wf: "wf_jvm_progΦ P" assumes cnf: "correct_state P Φ σ" theorem (in cnf) no_type_errors: "P \<turnstile> (Normal σ) -tas-jvmd->* σ' ==> σ' ≠ TypeError" apply (unfold exec_star_d_def) apply(insert cnf) apply(erule rtrancl3p_induct1) apply(simp) apply(fold exec_star_d_def) apply(insert wf) apply(clarsimp) apply(drule defensive_imp_aggressive) apply (frule (2) BV_correct) apply (drule (1) no_type_error) back apply(erule exec_1_d.cases) apply(simp) apply(fastsimp) done locale start = fixes P and C and M and σ and T and b assumes wf: "wf_jvm_prog P" assumes sees: "P \<turnstile> C sees M:[]->T = b in C" defines "σ ≡ Normal (start_state P C M)" corollary (in start) bv_no_type_error: shows "P \<turnstile> σ -tas-jvmd->* σ' ==> σ' ≠ TypeError" proof - from wf obtain Φ where "wf_jvm_progΦ P" by (auto simp: wf_jvm_prog_def) moreover with sees have "correct_state P Φ (start_state P C M)" by - (rule BV_correct_initial) ultimately have "cnf P Φ (start_state P C M)" by (rule cnf.intro) moreover assume "P \<turnstile> σ -tas-jvmd->* σ'" ultimately show ?thesis by (unfold σ_def) (rule cnf.no_type_errors) qed end