diff --git a/theories/tree_borrows/README.md b/theories/tree_borrows/README.md index 833fff0a37e645c047c07d2dd09dc05f37fd4e63..fc6a8dcec3d71220503849b9a8cefc19671d31b4 100644 --- a/theories/tree_borrows/README.md +++ b/theories/tree_borrows/README.md @@ -12,6 +12,9 @@ Forked and adapted from the sibling folder `../stacked_borrows` with the same st * `wf.v` defines well-formedness for expressions. * `steps_progress.v` states success conditions for the various borrow steps so that we can prove absence of UB or exploit presence of UB. * `tkmap_view.v` defines views (partial ownership) of the global maps we use to remember the kind of each tag +* `trees_equal/` contains a number of files related to a `trees_equal` binary relation between trees. + In Stacked Borrows the source stack and the target stack are always identical. + In Tree Borrows that is no longer the case, and this relation describes the extent to which they are allowed to differ. * `logical_state.v` defines the invariants and instantiates the simulation relation, using among others a notion of when trees are similar in `trees_equal/`. * `tag_protected_laws.v` contains reasoning principles about protectors diff --git a/theories/tree_borrows/trees_equal/trees_equal.v b/theories/tree_borrows/trees_equal/trees_equal.v deleted file mode 100644 index 9cf406198ac56d15f707aa595576c792f3825227..0000000000000000000000000000000000000000 --- a/theories/tree_borrows/trees_equal/trees_equal.v +++ /dev/null @@ -1,4166 +0,0 @@ -(** This file provides the basic heap and ghost state support for the BorIngLang program logic. *) -From iris.proofmode Require Export proofmode. -From iris.bi.lib Require Import fractional. -From iris.base_logic.lib Require Import ghost_map. -From simuliris.base_logic Require Export gen_sim_prog. -From simuliris.simulation Require Export slsls gen_log_rel. -From simuliris.simulation Require Import lifting. -From simuliris.tree_borrows Require Import tkmap_view. -From simuliris.tree_borrows Require Export defs. -From simuliris.tree_borrows Require Export steps_wf. -From simuliris.tree_borrows Require Import steps_progress. -From iris.prelude Require Import options. - - -Section utils. - - Definition tag_valid (upper : tag) (n : tag) : Prop := (n < upper)%nat. - - Lemma tag_valid_mono upper1 upper2 n1 n2 : - tag_valid upper1 n1 → - (upper1 ≤ upper2)%nat → - (n2 ≤ n1)%nat → - tag_valid upper2 n2. - Proof. - rewrite /tag_valid. lia. - Qed. - - Context (C : gset call_id). - - (* trees_equal is almost symmetric. To still get nice reasoning rules around symmetry and stuff, - we add a directionality flags for all rules that hold on both sides, so that we can reason by - symmetry -> foo -> symmetry and so only have to formulate foo to operate on one side *) - Inductive direction := Forwards | Backwards. - - Inductive pseudo_conflicted (tr : tree item) (tg : tag) (l : Z) - : res_conflicted → Prop := - | pseudo_conflicted_conflicted : - (* a Conflicted marker makes the permission literally conflicted *) - pseudo_conflicted tr tg l ResConflicted - | pseudo_conflicted_cousin_init tg_cous it_cous : - (* If it's not actually conflicted, it can be pseudo conflicted if there is *) - (* A cousin that is protected *) - rel_dec tr tg tg_cous = Foreign Cousin -> - tree_lookup tr tg_cous it_cous -> - protector_is_active it_cous.(iprot) C -> - (* and who on this location is initalized not disabled *) - (item_lookup it_cous l).(perm) ≠Disabled -> - (item_lookup it_cous l).(initialized) = PermInit -> - pseudo_conflicted tr tg l ResActivable - . - - Inductive pseudo_disabled (tr : tree item) (tg : tag) (l : Z) : permission → (option protector) → Prop := - | pseudo_disabled_disabled prot : - (* a Disabled it also pseudo-disabled *) - pseudo_disabled _ _ _ Disabled prot - | pseudo_disabled_cousin_active tg_cous it_cous lp prot : - rel_dec tr tg tg_cous = Foreign Cousin -> - tree_lookup tr tg_cous it_cous -> - protector_is_active it_cous.(iprot) C -> - (item_lookup it_cous l) = mkPerm PermInit Active -> - (* This is not allowed, since it actually survives foreign writes. *) - lp ≠ReservedIM -> - pseudo_disabled _ _ _ lp prot - . - - (* this implicitly requires (by state_wf) that it's not (protected and initialized) *) - (* it also implies (via state_wf) that all children are not (protected and initialized) *) - Inductive is_disabled (tr : tree item) (tg : tag) (l : Z) : lazy_permission → option protector → Prop := - | disabled_init prot : - is_disabled _ _ _ (mkPerm PermInit Disabled) prot - | disabled_pseudo lp prot : - pseudo_disabled tr tg l lp prot → - is_disabled _ _ _ (mkPerm PermLazy lp) prot. - - Inductive disabled_in_practice (tr : tree item) (tg : tag) (witness : tag) (l : Z) - : Prop := - | disabled_parent it_witness inclusive : - (* Doesn't have to be immediate, just any parent is Disabled *) - rel_dec tr tg witness = Child inclusive -> - tree_lookup tr witness it_witness -> - is_disabled tr witness l (item_lookup it_witness l) (iprot it_witness) -> - disabled_in_practice tr tg witness l - . - - Inductive parent_has_perm p (tr : tree item) (tg : tag) (witness : tag) (l : Z) - : Prop := - (* This means being Reserved and having a parent that is exactly Frozen. - [frozen_in_practice] behaves indistinguishably from Frozen. - We could probably make [Frozen] and [frozen_in_practice] equivalent, but - this shouldn't turn up in practice. *) - | mk_parent_has_perm it_witness inclusive : - rel_dec tr tg witness = Child inclusive -> - tree_lookup tr witness it_witness -> - (item_lookup it_witness l).(perm) = p -> - (* be initialized so that protectors trigger if applicable *) - (item_lookup it_witness l).(initialized) = PermInit -> - parent_has_perm p tr tg witness l - . - - Definition frozen_in_practice := parent_has_perm Frozen. - - Inductive one_sided_sim : Prop -> permission -> permission -> Prop := - | one_sided_sim_active isprot : - ¬ isprot -> - one_sided_sim isprot Frozen Active - | one_sided_sim_res_confl isprot : - isprot -> - one_sided_sim isprot (Reserved ResConflicted) (Reserved ResActivable). - - Definition directional_simulation d isprot p1 p2 : Prop := - match d with - | Forwards => one_sided_sim isprot p1 p2 - | Backwards => one_sided_sim isprot p2 p1 - end. - - Inductive perm_eq_up_to_C (tr1 tr2 : tree item) (tg : tag) (l : Z) cid d - : lazy_permission -> lazy_permission -> Prop := - | perm_eq_up_to_C_refl p : - (* Usually the permissions will be equal *) - perm_eq_up_to_C tr1 tr2 tg l cid d p p - | perm_eq_up_to_C_pseudo ini confl1 confl2 : - (* But if they are protected *) - protector_is_active cid C -> - (* And both pseudo-conflicted *) - pseudo_conflicted tr1 tg l confl1 -> - pseudo_conflicted tr2 tg l confl2 -> - (* then we can allow a small difference *) - perm_eq_up_to_C tr1 tr2 tg l cid d - {| initialized := ini; perm := Reserved confl1 |} - {| initialized := ini; perm := Reserved confl2 |} - | perm_eq_up_to_C_pseudo_post_prot ini confl1 confl2 : - (* But if they are not protected *) - ¬ protector_is_active cid C -> - (* then we can allow a small difference *) - perm_eq_up_to_C tr1 tr2 tg l cid d - {| initialized := ini; perm := Reserved confl1 |} - {| initialized := ini; perm := Reserved confl2 |} - | perm_eq_up_to_C_pseudo_disabled p1 p2 : - (* A pseudo-disabled tag is one that's lazy, does not support child accesses due to a protected Active cousin, - and will become Disabled on protector-end write for that cousin. - It must be lazy, because a protected active has no non-disabled initialized cousins. - Only exception: ¬prot Reserved InteriorMut, for which this case here does not apply. *) - pseudo_disabled tr1 tg l p1 cid -> - pseudo_disabled tr2 tg l p2 cid -> - perm_eq_up_to_C tr1 tr2 tg l cid d - {| initialized := PermLazy; perm := p1 |} - {| initialized := PermLazy; perm := p2 |} - | perm_eq_up_to_C_disabled_parent witness_tg p p' : - (* Finally if they have a Disabled parent we allow anything (unprotected) since - nothing is possible through this tag anyway *) - disabled_in_practice tr1 tg witness_tg l -> - disabled_in_practice tr2 tg witness_tg l -> - (* Added initialization requirement to help with the lemma [perm_eq_up_to_C_same_init] *) - (initialized p = initialized p') -> - perm_eq_up_to_C tr1 tr2 tg l cid d p p' - | perm_eq_up_to_C_frozen_parent ini confl1 confl2 witness_tg : - (* not needed for IM, that's already covered by refl *) - (* only the source side must be Frozen. This already implies the other side is frozen in practice, - or the same with Active, or we're disabled on both. *) - frozen_in_practice (match d with Forwards => tr1 | _ => tr2 end) tg witness_tg l -> - perm_eq_up_to_C tr1 tr2 tg l cid d - {| initialized := ini; perm := Reserved confl1 |} - {| initialized := ini; perm := Reserved confl2 |} - | perm_eq_up_to_C_directional p1 p2 ini : - directional_simulation d (protector_is_active cid C) p1 p2 -> - perm_eq_up_to_C tr1 tr2 tg l cid d - {| initialized := ini; perm := p1 |} - {| initialized := ini; perm := p2 |} - . - - Definition loc_eq_up_to_C (tr1 tr2 : tree item) (tg : tag) d (it1 it2 : item) (l : Z) := - it1.(iprot) = it2.(iprot) - /\ perm_eq_up_to_C tr1 tr2 tg l it1.(iprot) d (item_lookup it1 l) (item_lookup it2 l). - - Definition item_eq_up_to_C (tr1 tr2 : tree item) (tg : tag) d (it1 it2 : item) := - forall l, loc_eq_up_to_C tr1 tr2 tg d it1 it2 l. - - Definition tree_equal d (tr1 tr2 : tree item) := - (* To be equal trees must have exactly the same tags *) - (forall tg, tree_contains tg tr1 <-> tree_contains tg tr2) - (* and define all the same relationships between those tags *) - /\ (forall tg tg', rel_dec tr1 tg tg' = rel_dec tr2 tg tg') - (* and have their permissions be equal up to C on all locations *) - (* FIXME: maybe think about reformulating ∧ (∀ t it1 it2, tree_lookup t it1 tr1 -> tree_lookup t it2 tr2 -> it_rel it1 it2) *) - /\ (forall tg, tree_contains tg tr1 -> - exists it1 it2, - tree_lookup tr1 tg it1 - /\ tree_lookup tr2 tg it2 - /\ item_eq_up_to_C tr1 tr2 tg d it1 it2 - ). - - Definition trees_equal d (t1 t2 : trees) := - ∀ blk, option_Forall2 (tree_equal d) (t1 !! blk) (t2 !! blk). - - - Lemma loc_eq_up_to_C_reflexive - {d tr1 tr2 tg it l} - : loc_eq_up_to_C tr1 tr2 tg d it it l. - Proof. - split. - + reflexivity. - + apply perm_eq_up_to_C_refl. - Qed. - - Lemma item_eq_up_to_C_reflexive - {d tr1 tr2 tg it} - : item_eq_up_to_C tr1 tr2 tg d it it. - Proof. - intro l. - apply loc_eq_up_to_C_reflexive. - Qed. - - Lemma tree_equal_reflexive d tr - (AllUnique : forall tg, tree_contains tg tr -> exists it, tree_item_determined tg it tr) - : tree_equal d tr tr. - Proof. - try repeat split. - - tauto. - - tauto. - - intros tg Ex. - destruct (AllUnique tg Ex). - eexists. eexists. - try repeat split. - + assumption. - + eassumption. - + assumption. - + eassumption. - + apply item_eq_up_to_C_reflexive. - Qed. - - - Lemma trees_equal_reflexive d trs - (AllUnique : forall blk tr tg, - trs !! blk = Some tr -> - tree_contains tg tr -> - exists it, tree_item_determined tg it tr) - : trees_equal d trs trs. - Proof. - intros blk. - specialize (AllUnique blk). - remember (trs !! blk) as at_blk. - destruct at_blk. - - apply Some_Forall2. - apply tree_equal_reflexive. - intro tg. - eapply AllUnique. - reflexivity. - - apply None_Forall2. - Qed. - - - Lemma trees_equal_same_tags d (trs1 trs2 : trees) (tg : tag) (blk : block) : - trees_equal d trs1 trs2 -> - trees_contain tg trs1 blk <-> trees_contain tg trs2 blk. - Proof. - intro Equals. - rewrite /trees_equal in Equals. - specialize (Equals blk). - rewrite /trees_contain /trees_at_block. - destruct (trs1 !! blk) as [tr1|]; - destruct (trs2 !! blk) as [tr2|]; - inversion Equals as [?? Equal|]. - 2: tauto. - subst. - destruct Equal as [SameTags _]. - apply SameTags. - Qed. - - Lemma trees_equal_empty d : trees_equal d ∅ ∅. - Proof. - apply trees_equal_reflexive. - intros blk tr tg LookupEmp. - inversion LookupEmp. - Qed. - - Definition direction_flip d := match d with - Forwards => Backwards - | Backwards => Forwards end. - - Lemma direction_flip_inv d : direction_flip (direction_flip d) = d. - Proof. by destruct d. Qed. - - Lemma perm_eq_up_to_C_sym - {d tr1 tr2 tg l cid perm1 perm2} - : perm_eq_up_to_C tr1 tr2 tg l cid d perm1 perm2 - -> perm_eq_up_to_C tr2 tr1 tg l cid (direction_flip d) perm2 perm1. - Proof. - intro EqC. - inversion EqC. - + econstructor 1. - + econstructor 2; eassumption. - + econstructor 3; eassumption. - + econstructor 4; eassumption. - + econstructor 5; try eassumption. - done. - + econstructor 6; destruct d; eassumption. - + econstructor 7; destruct d; eassumption. - Qed. - - Lemma loc_eq_up_to_C_sym - {d tr1 tr2 tg it1 it2 l} - : loc_eq_up_to_C tr1 tr2 tg d it1 it2 l - -> loc_eq_up_to_C tr2 tr1 tg (direction_flip d) it2 it1 l. - Proof. - intros [SameProt EqC]. - split. - + auto. - + apply perm_eq_up_to_C_sym. - rewrite <- SameProt. - assumption. - Qed. - - Lemma item_eq_up_to_C_sym - {d tr1 tr2 tg it1 it2} - : item_eq_up_to_C tr1 tr2 tg d it1 it2 - -> item_eq_up_to_C tr2 tr1 tg (direction_flip d) it2 it1. - Proof. - intros EqC l. - apply loc_eq_up_to_C_sym. - auto. - Qed. - - Lemma tree_equal_sym {d} tr1 tr2 : tree_equal d tr1 tr2 → tree_equal (direction_flip d) tr2 tr1. - Proof. - rewrite /tree_equal. - intros [SameTg [SameRel EqC]]. - split; [|split]. - + intro tg. rewrite SameTg. tauto. - + intros tg tg'. rewrite SameRel. tauto. - + intros tg Ex. - rewrite <- SameTg in Ex. - destruct (EqC tg Ex) as [it1 [it2 [Lookup1 [Lookup2 EqCsub]]]]. - exists it2, it1. - split; [|split]. - * assumption. - * assumption. - * apply item_eq_up_to_C_sym. - assumption. - Qed. - - Lemma trees_equal_sym {d} trs1 trs2 : trees_equal d trs1 trs2 → trees_equal (direction_flip d) trs2 trs1. - Proof. - rewrite /trees_equal. - intros Equals blk. - specialize (Equals blk). - inversion Equals; simplify_eq; econstructor. - by eapply tree_equal_sym. - Qed. - - Lemma every_node_iff_every_lookup - {tr prop} - (GloballyUnique : forall tg, tree_contains tg tr -> exists it, tree_item_determined tg it tr) - : every_node prop tr <-> forall tg it, tree_lookup tr tg it -> prop it. - Proof. - rewrite every_node_eqv_universal. - split. - - intros Every tg it [Ex Unq]. - apply Every. - eapply exists_node_increasing; [eassumption|]. - eapply every_node_increasing; [eassumption|]. - erewrite every_node_eqv_universal. - intros. symmetry. auto. - - intros Lookup it Exists. - apply (Lookup (itag it)). - assert (tree_contains it.(itag) tr) as Ex. { - eapply exists_node_increasing; [eassumption|]. - erewrite every_node_eqv_universal. - intros. subst. auto. - } - destruct (GloballyUnique _ Ex) as [it' Unq']. - assert (it = it') as Eq. { - apply (proj1 (every_node_eqv_universal _ _) Unq' it Exists). - auto. - } - rewrite -Eq in Unq'. - split; assumption. - Qed. - - Lemma tree_equal_implies_globally_unique_1 - {d tr1 tr2} : - tree_equal d tr1 tr2 -> - forall tg, tree_contains tg tr1 -> exists it, tree_item_determined tg it tr1. - Proof. - intros [ExIff [SameRel Lookup]] tg Ex. - destruct (Lookup _ Ex) as [it1 [it2 [Lookup1 [Lookup2 EqC]]]]. - exists it1. - apply Lookup1. - Qed. - - Lemma tree_equal_implies_globally_unique_2 - {d tr1 tr2} : - tree_equal d tr1 tr2 -> - forall tg, tree_contains tg tr2 -> exists it, tree_item_determined tg it tr2. - Proof. - intro Eq. - pose proof (tree_equal_sym _ _ Eq) as Eq'. - revert Eq'. - apply tree_equal_implies_globally_unique_1. - Qed. - - - Lemma tree_equal_transfer_lookup_1 - {d tr1 tr2 tg it1} : - tree_equal d tr1 tr2 -> - tree_lookup tr1 tg it1 -> - exists it2, - tree_lookup tr2 tg it2 - /\ item_eq_up_to_C tr1 tr2 tg d it1 it2. - Proof. - intros [SameTg [SameRel MkLookup]] [Ex1 Unq1]. - destruct (MkLookup _ Ex1) as [it1' [it2 [Lookup1' [Lookup2 EqC']]]]. - assert (it1 = it1') by (eapply tree_determined_unify; [eassumption|apply Unq1|apply Lookup1']). - subst it1'. - exists it2. - split; assumption. - Qed. - - Lemma tree_equal_transfer_lookup_2 - {d tr1 tr2 tg it2} : - tree_equal d tr1 tr2 -> - tree_lookup tr2 tg it2 -> - exists it1, - tree_lookup tr1 tg it1 - /\ item_eq_up_to_C tr1 tr2 tg d it1 it2. - Proof. - intros Eq Lookup2. - pose proof (tree_equal_sym _ _ Eq) as Eq'. - destruct (tree_equal_transfer_lookup_1 Eq' Lookup2) as [it1 [Lookup1 EqC']]. - exists it1; split; [assumption|]. - rewrite -(direction_flip_inv d). - apply item_eq_up_to_C_sym. - assumption. - Qed. - - Lemma is_Some_ignore_bind - {X Y} {o : option X} {g : X -> Y} : - is_Some (o ≫= fun x => Some (g x)) <-> is_Some o. - Proof. - destruct o; simpl; split; intro H. - - auto. - - auto. - - inversion H; discriminate. - - inversion H; discriminate. - Qed. - - Lemma mutual_parent_child_both_or_neither - {tg tg' tr} : - StrictParentChildIn tg tg' tr -> - StrictParentChildIn tg' tg tr -> - forall br, - exists_subtree (eq br) tr -> - (tree_contains tg (of_branch br) <-> tree_contains tg' (of_branch br)). - Proof. - intros Rel Rel' br ExBr. - destruct (decide (tree_contains tg (of_branch br))) as [Ex|nEx]. - all: destruct (decide (tree_contains tg' (of_branch br))) as [Ex'|nEx']. - all: try tauto. - all: exfalso. - - enough (tree_contains tg' (of_branch br)) by contradiction. - rewrite /StrictParentChildIn every_subtree_eqv_universal in Rel. - pose proof (proj1 (exists_node_iff_exists_root _ _) Ex) as WitnessSubtree. - rewrite exists_subtree_eqv_existential in WitnessSubtree. - destruct WitnessSubtree as [br' [ExBr' TgRoot]]. - assert (exists_subtree (eq br') tr) as ExBr'' by (eapply exists_subtree_transitive; eauto). - specialize (Rel br' ExBr'' TgRoot). - eapply exists_node_transitive. - + eassumption. - + simpl in TgRoot. - destruct br' as [[]]; simpl in *. - right; right; assumption. - - enough (tree_contains tg (of_branch br)) by contradiction. - rewrite /StrictParentChildIn every_subtree_eqv_universal in Rel'. - pose proof (proj1 (exists_node_iff_exists_root _ _) Ex') as WitnessSubtree. - rewrite exists_subtree_eqv_existential in WitnessSubtree. - destruct WitnessSubtree as [br' [ExBr' TgRoot]]. - assert (exists_subtree (eq br') tr) as ExBr'' by (eapply exists_subtree_transitive; eauto). - specialize (Rel' br' ExBr'' TgRoot). - eapply exists_node_transitive. - + eassumption. - + simpl in TgRoot. - destruct br' as [[]]; simpl in *. - right; right; assumption. - Qed. - - Lemma involution_of_branch - {X} {data : X} {tr1 tr2} - : branch data tr1 tr2 = of_branch (data, tr1, tr2). - Proof. reflexivity. Qed. - - Lemma strict_parent_self_impossible - {tg tr} : - tree_contains tg tr -> - StrictParentChildIn tg tg tr -> - False. - Proof. - intros Ex Strict. - induction tr as [|? ? IHtr1 ? IHtr2]; [inversion Ex|]. - inversion Strict as [Strict0 [Strict1 Strict2]]. - inversion Ex as [Ex0 | [Ex1 | Ex2]]. - - apply IHtr2. - + apply Strict0. assumption. - + assumption. - - apply IHtr1; assumption. - - apply IHtr2; assumption. - Qed. - - Lemma mutual_strict_parent_child_impossible - {tg tg' tr} : - tree_contains tg tr -> - tree_contains tg' tr -> - StrictParentChildIn tg tg' tr -> - StrictParentChildIn tg' tg tr -> - False. - Proof. - intros Ex Ex' Rel Rel'. - enough (StrictParentChildIn tg tg tr). - + eapply strict_parent_self_impossible. - * exact Ex. - * assumption. - + eapply StrictParentChild_transitive; eassumption. - Qed. - - Lemma mutual_parent_child_implies_equal - {tg tg' tr} : - tree_contains tg tr -> - tree_contains tg' tr -> - ParentChildIn tg tg' tr -> - ParentChildIn tg' tg tr -> - tg' = tg. - Proof. - rewrite /ParentChildIn. - intros Ex Ex'. - intros [|StrictRel]; [auto|]. - intros [|StrictRel']; [auto|]. - exfalso. - eapply mutual_strict_parent_child_impossible. - + exact Ex. - + exact Ex'. - + assumption. - + assumption. - Qed. - - Lemma rel_this_antisym - {tr tg tg'} : - tree_contains tg tr -> - tree_contains tg' tr -> - rel_dec tr tg tg' = Child This -> tg = tg'. - Proof. - rewrite /rel_dec. - remember (decide (ParentChildIn tg tg' tr)) as Rel. - remember (decide (ParentChildIn tg' tg tr)) as Rel'. - destruct Rel; destruct Rel'. - all: try (intro; discriminate). - intros Ex Ex' _. - eapply mutual_parent_child_implies_equal; eauto. - Qed. - - Lemma rel_dec_refl tr tg : - rel_dec tr tg tg = Child This. - Proof. - rewrite /rel_dec. - rewrite decide_True; [|left; reflexivity]. - rewrite decide_True; [|left; reflexivity]. - reflexivity. - Qed. - - Lemma child_of_this_is_foreign_for_cousin - {tr tg_this tg_cous tg_child} : - tree_unique tg_this tr -> - tree_unique tg_cous tr -> - tree_unique tg_child tr -> - rel_dec tr tg_this tg_cous = Foreign Cousin -> - (if rel_dec tr tg_child tg_this is Child _ then True else False) -> - rel_dec tr tg_child tg_cous = Foreign Cousin. - Proof. - intros Ex_this Ex_cous Ex_child. - intros Rel_this_cous Rel_child_this_Foreign. - destruct (rel_dec _ tg_child _) as [|pos] eqn:Rel_child_this; [contradiction|]. - destruct pos. - + rewrite /rel_dec in Rel_this_cous, Rel_child_this |- *. - repeat destruct (decide (ParentChildIn _ _ _)); try discriminate. - - enough (ParentChildIn tg_this tg_cous tr) by contradiction. - eapply ParentChild_transitive; eassumption. - - exfalso. - eapply cousins_have_disjoint_children with (tg1 := tg_this) (tg2 := tg_cous). - * eassumption. - * assumption. - * assumption. - * rewrite /rel_dec. - rewrite decide_False; [|eassumption]. - rewrite decide_False; [|eassumption]. - reflexivity. - * eassumption. - * eassumption. - - enough (ParentChildIn tg_this tg_cous tr) by contradiction. - eapply ParentChild_transitive; eassumption. - - reflexivity. - + rewrite (rel_this_antisym _ _ Rel_child_this); first assumption. - all: apply unique_exists; assumption. - Qed. - - Lemma cousin_write_for_initialized_protected_nondisabled_is_ub - {it l acc_tg tr range tg b} - (Lookup : tree_lookup tr tg it) - (Protected : protector_is_active (iprot it) C) - (IsInit : initialized (item_lookup it l) = PermInit) - (IsCousin : rel_dec tr acc_tg tg = Foreign Cousin) - (InRange : range'_contains range l) - : ~ is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm AccessWrite)) C acc_tg range tr). - Proof. - intro Absurd. - rewrite -apply_access_success_condition in Absurd. - rewrite every_node_eqv_universal in Absurd. - specialize (Absurd it). - assert (itag it = tg) as Tg. { eapply tree_determined_specifies_tag; apply Lookup. } - rewrite Tg in Absurd. - rewrite IsCousin in Absurd. - rewrite /item_apply_access /permissions_apply_range' in Absurd. - rewrite is_Some_ignore_bind in Absurd. - rewrite -mem_apply_range'_success_condition in Absurd. - rewrite bool_decide_eq_true_2 in Absurd; [|auto]. - enough (is_Some (apply_access_perm AccessWrite (Foreign Cousin) true (item_lookup it l))) as Absurd'. - - rewrite /apply_access_perm in Absurd'. - destruct (item_lookup _ _) as [[] [[]| | | |]], b; simpl in Absurd'. - all: try inversion Absurd'; discriminate. - - rewrite /item_lookup. setoid_rewrite maybe_non_children_only_no_effect in Absurd; last done. - apply Absurd; [|done]. - eapply exists_determined_exists; apply Lookup. - Qed. - - Lemma pseudo_conflicted_allows_more_access - {tr1 tr2 tg l confl1 confl2 kind rel isprot ini acc_tg range it1 b} - (* Main hypotheses *) - (Confl1 : pseudo_conflicted tr1 tg l confl1) - (Confl2 : pseudo_conflicted tr2 tg l confl2) - (AccEx : tree_unique acc_tg tr1) - (TgEx : tree_unique tg tr1) - (* Auxiliary stuff to bind the local access to the global success for the pseudo conflicted case *) - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GlobalSuccess : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1)) - (ProtSpec : isprot = bool_decide (protector_is_active (iprot it1) C)) - (RelSpec : rel = rel_dec tr1 acc_tg tg) - (PermSpec : item_lookup it1 l = {| initialized := ini; perm := Reserved confl1 |}) - (InRange : range'_contains range l) - : is_Some - (apply_access_perm kind rel isprot - {| initialized := ini; perm := Reserved confl1 |}) - -> is_Some - (apply_access_perm kind rel isprot - {| initialized := ini; perm := Reserved confl2 |}). - Proof. - rewrite /apply_access_perm /apply_access_perm_inner; simpl. - (* Most cases are by reflexivity. *) - destruct kind, rel; simpl. - all: destruct ini, isprot; simpl; try auto. - all: inversion Confl1 as [|?? RelCous LookupCous]. - all: inversion Confl2. - all: subst; simpl; try auto. - (* Once we get reflexivity out of the way we are left with the accesses - where there is UB in the target because of the conflicted. - We now need to prove that actually there is also UB in the source, - just not _here_, instead it occured at the cousin that creates the conflict. *) - all: exfalso. - (* FIXME: here we need a lemma that shows - 1. a Child/This access for tg is Foreign for tg_cous who is Cousin of tg - 2. a Foreign access for such tg_cous is UB globally. - We can indeed check that in all of the following cases we have - rel = This or rel = Child and kind = AccessWrite. *) - all: eapply cousin_write_for_initialized_protected_nondisabled_is_ub. - all: try exact GlobalSuccess. - all: try eassumption. - all: eapply child_of_this_is_foreign_for_cousin. - all: try apply RelCous. - all: try assumption. - all: try rewrite -RelSpec; auto. - all: apply GloballyUnique1; apply LookupCous. - Qed. - - Lemma pseudo_conflicted_post_prot_allows_more_access - {tr1 tg l confl1 confl2 kind rel isprot ini acc_tg range it1 b} - (* Main hypotheses *) - (AccEx : tree_unique acc_tg tr1) - (TgEx : tree_unique tg tr1) - (* Auxiliary stuff to bind the local access to the global success for the pseudo conflicted case *) - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GlobalSuccess : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1)) - (NoProp : ¬ protector_is_active (iprot it1) C) - (ProtSpec : isprot = bool_decide (protector_is_active (iprot it1) C)) - (RelSpec : rel = rel_dec tr1 acc_tg tg) - (PermSpec : item_lookup it1 l = {| initialized := ini; perm := Reserved confl1 |}) - (InRange : range'_contains range l) - : is_Some - (apply_access_perm kind rel isprot - {| initialized := ini; perm := Reserved confl1 |}) - -> is_Some - (apply_access_perm kind rel isprot - {| initialized := ini; perm := Reserved confl2 |}). - Proof. - rewrite /apply_access_perm /apply_access_perm_inner; simpl. - rewrite bool_decide_false in ProtSpec; last done. subst isprot. - (* Most cases are by reflexivity. *) - destruct kind, rel; simpl. - all: destruct ini; simpl; try auto. - all: subst; simpl; try auto. - all: destruct confl1, confl2. - all: subst; simpl; try auto. - Qed. - - Lemma pseudo_disabled_allows_more_access - {tr1 tr2 tg l p1 p2 kind rel isprot acc_tg range it1 b} - (* Main hypotheses *) - (Confl1 : pseudo_disabled tr1 tg l p1 (iprot it1)) - (Confl2 : pseudo_disabled tr2 tg l p2 (iprot it1)) - (AccEx : tree_unique acc_tg tr1) - (TgEx : tree_unique tg tr1) - (* Auxiliary stuff to bind the local access to the global success for the pseudo conflicted case *) - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GlobalSuccess : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1)) - (ProtSpec : isprot = bool_decide (protector_is_active (iprot it1) C)) - (RelSpec : rel = rel_dec tr1 acc_tg tg) - (PermSpec : item_lookup it1 l = {| initialized := PermLazy; perm := p1 |}) - (InRange : range'_contains range l) - : is_Some - (apply_access_perm kind rel isprot - {| initialized := PermLazy; perm := p1 |}) - -> is_Some - (apply_access_perm kind rel isprot - {| initialized := PermLazy; perm := p2 |}). - Proof. - rewrite /apply_access_perm /apply_access_perm_inner; simpl. - destruct rel; last first. - - inversion Confl1 as [H1 H2|tg_cs it_cs X1 X2 Hcs Hlu Hluact Hpp XX X3]; simplify_eq. - 1: destruct kind; simpl; intros [? [=]]. - exfalso. eapply apply_access_success_condition in GlobalSuccess. - eapply every_node_eqv_universal in GlobalSuccess. - 2: eapply tree_lookup_to_exists_node, Hlu. - rewrite /item_apply_access /permissions_apply_range' in GlobalSuccess. - erewrite is_Some_ignore_bind in GlobalSuccess. - eapply mem_apply_range'_success_condition in GlobalSuccess. - 2: exact InRange. - rewrite /rel_dec in GlobalSuccess. - assert (itag it_cs = tg_cs) as Hcstg by by eapply tree_lookup_correct_tag. - rewrite decide_False in GlobalSuccess. - 2: { intros HPC. eapply cousins_have_disjoint_children. - 4: exact Hcs. 2: done. 1: exact AccEx. - 1: eapply GloballyUnique1, Hlu. 2: by subst. - rewrite /rel_dec in RelSpec. destruct decide in RelSpec; done. } - rewrite decide_False in GlobalSuccess. - 2: { intros HPC. rewrite /rel_dec in RelSpec Hcs. - destruct decide as [HP1|?] in RelSpec; try done. - destruct decide as [?|HnP1] in Hcs; try done. - destruct decide as [?|HnP2] in Hcs; try done. - eapply HnP2. eapply ParentChild_transitive. - 1: exact HP1. subst. done. } - rewrite /item_lookup in Hpp. - rewrite Hpp bool_decide_true // in GlobalSuccess. - rewrite maybe_non_children_only_no_effect // in GlobalSuccess. - destruct kind; destruct GlobalSuccess as [x [=]]. - - rewrite /=. intros _. destruct kind, isprot, p2 as [[]| | | |]; simpl; done. - Qed. - - (* FIXME: move this elsewhere *) - Lemma if_fun_absorb_args {X Y} {b : bool} {x : X} {f g : X -> Y} : - (if b then f else g) x = if b then f x else g x. - Proof. destruct b; reflexivity. Qed. - - Lemma rel_dec_child_transitive - {tr tg1 tg2 tg3 incl1 incl2} - : rel_dec tr tg1 tg2 = Child incl1 -> - rel_dec tr tg2 tg3 = Child incl2 -> - exists incl3, rel_dec tr tg1 tg3 = Child incl3. - Proof. - intros Rel12 Rel23. - unfold rel_dec in *. - destruct (decide (ParentChildIn tg2 tg1 tr)); last congruence. - destruct (decide (ParentChildIn tg3 tg2 tr)); last congruence. - assert (ParentChildIn tg3 tg1 tr) by (eapply ParentChild_transitive; eassumption). - eexists. - destruct (decide (ParentChildIn tg3 tg1 tr)); last contradiction. - f_equal. - Qed. - - Lemma frozen_in_practice_rejects_child_write - {tr tg witness l b acc_tg range} - (InRange : range'_contains range l) - (GloballyUnique : forall tg, tree_contains tg tr -> tree_unique tg tr) - (Frz : frozen_in_practice tr tg witness l) - (Acc : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm AccessWrite)) C acc_tg range tr)) - (Rel : exists x, rel_dec tr acc_tg tg = Child x) - : False. - Proof. - inversion Frz as [it_witness ? Rel' Lkup Perm]. - rewrite -apply_access_success_condition in Acc. - rewrite every_node_iff_every_lookup in Acc. 2: { - intros tg0 Ex0. apply unique_lookup. apply GloballyUnique. assumption. - } - specialize (Acc _ _ Lkup). - assert (exists x, rel_dec tr acc_tg witness = Child x) as FullRel. 1: { - destruct Rel as [? Rel]. - eapply rel_dec_child_transitive; eassumption. - } - destruct FullRel as [? FullRel]. - assert (itag it_witness = witness) as WitnessTg. { - eapply tree_determined_specifies_tag; apply Lkup. - } - rewrite WitnessTg FullRel in Acc. - unfold item_apply_access, maybe_non_children_only in Acc. - unfold is_Some in Acc. - destruct Acc as [? Acc]. - rewrite bind_Some in Acc. - destruct Acc as [? [Acc Res]]. - injection Res; clear Res; intros; subst. - unfold permissions_apply_range' in Acc. - pose proof (mk_is_Some _ _ Acc) as AccSome; clear Acc. - rewrite -mem_apply_range'_success_condition in AccSome. - specialize (AccSome l InRange). - do 4 rewrite if_fun_absorb_args in AccSome. - unfold nonchildren_only in AccSome. - rewrite Tauto.if_same in AccSome. - unfold apply_access_perm, apply_access_perm_inner in AccSome. - rewrite Perm in AccSome. - simpl in AccSome. - inversion AccSome; congruence. - Qed. - - Lemma loc_eq_up_to_C_allows_more_access - {d tr1 tr2 tg it1 it2 l kind acc_tg range b} - (Tg1 : itag it1 = tg) - (Tg2 : itag it2 = tg) - (UnqAcc : tree_unique acc_tg tr1) - (UnqAcc2 : tree_unique acc_tg tr2) - (Ex1 : tree_unique tg tr1) - (Ex2 : tree_lookup tr2 tg it2) - (SameRel : forall tg tg', rel_dec tr1 tg tg' = rel_dec tr2 tg tg') - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (ParentsMoreInit : parents_more_init tr2) - (GlobalSuccess : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1)) - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (InRange : range'_contains range l) - (Hrestrict : kind = AccessWrite → d = Forwards) - : - loc_eq_up_to_C tr1 tr2 tg d it1 it2 l -> - is_Some (maybe_non_children_only b (apply_access_perm kind) (rel_dec tr1 acc_tg (itag it1)) - (bool_decide (protector_is_active (iprot it1) C)) - (item_lookup it1 l)) - -> - is_Some (maybe_non_children_only b (apply_access_perm kind) (rel_dec tr2 acc_tg (itag it2)) - (bool_decide (protector_is_active (iprot it2) C)) - (item_lookup it2 l)). - Proof. - intros EqC Acc1. - inversion EqC as [EqProt EqCLookup]. - inversion EqCLookup as - [perm Lookup EqLookup - |??? Prot Confl1 Confl2 Lookup1 Lookup2 - |??? Prot Lookup1 Lookup2 - |p1 p2 Confl1 Confl2 Lookup1 Lookup2 - |witness_tg ?? Dis1 Dis2 Lookup1 Lookup2 - |ini ?? witness_tg Frz Lookup1 Lookup2 - |p1 p2 ini Hd Lookup1 Lookup2 - ]. - - rewrite Tg2 -Tg1. - rewrite -SameRel. - rewrite -EqProt. - apply Acc1. - - rewrite Lookup2. - rewrite -Lookup1 in Acc1. - edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]. - 2: by erewrite Heq. - rewrite Heq. rewrite -Lookup2. - eapply (pseudo_conflicted_allows_more_access Confl1 Confl2 UnqAcc Ex1 GloballyUnique1 GlobalSuccess). - + rewrite -EqProt; reflexivity. - + rewrite SameRel -Tg2 //=. - + rewrite /item_lookup Lookup1 //=. - + exact InRange. - + rewrite Tg1 -Tg2 SameRel EqProt Heq // in Acc1. - - rewrite Lookup2. - rewrite -Lookup1 in Acc1. - edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]. - 2: by erewrite Heq. - rewrite Heq. rewrite -Lookup2. - eapply (pseudo_conflicted_post_prot_allows_more_access UnqAcc Ex1 GloballyUnique1 GlobalSuccess). - + done. - + rewrite -EqProt; reflexivity. - + rewrite SameRel -Tg2 //=. - + symmetry. apply Lookup1. - + exact InRange. - + rewrite Tg1 -Tg2 SameRel EqProt Heq // in Acc1. - - rewrite Lookup2. - rewrite -Lookup1 in Acc1. - edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]. - 2: by erewrite Heq. - rewrite Heq. rewrite -Lookup2. - eapply (pseudo_disabled_allows_more_access Confl1 Confl2 UnqAcc Ex1 GloballyUnique1 GlobalSuccess). - + rewrite -EqProt; reflexivity. - + rewrite SameRel -Tg2 //=. - + rewrite /item_lookup Lookup1 //=. - + exact InRange. - + rewrite Tg1 -Tg2 SameRel EqProt Heq // in Acc1. - - (* FIXME: there has to be a shorter proof *) - (* This has to be a foreign access *) - destruct (rel_dec tr1 acc_tg (itag it1)) eqn:AccRel; last first. - + (* If it's a child access then it's also a child access for the Disabled parent. *) - inversion Dis1 as [it_witness ? RelWitness LookupWitness DisWitnessPre]. - destruct (decide (perm (item_lookup it_witness l) = Disabled)) as [Hdis|HNonDis]; simplify_eq. - * rewrite <- apply_access_success_condition in GlobalSuccess. - rewrite every_node_iff_every_lookup in GlobalSuccess. 2: { - intros tg0 Ex0. apply unique_lookup. apply GloballyUnique1. assumption. - } - specialize (GlobalSuccess _ _ LookupWitness). - pose proof (tree_determined_specifies_tag _ _ _ (proj1 LookupWitness) (proj2 LookupWitness)) - as WitnessTg. - subst witness_tg. - assert (match rel_dec tr1 acc_tg (itag it_witness) with - | Child _ => True - | Foreign _ => False - end - ). { - unfold rel_dec in RelWitness. - destruct (decide _); last discriminate. - unfold rel_dec in AccRel. - destruct (decide _); last discriminate. - unfold rel_dec. - destruct (decide (ParentChildIn (itag it_witness) acc_tg tr1)) as [|WitnessAccRel]; first done. - apply WitnessAccRel. - eapply ParentChild_transitive. - + eassumption. - + eassumption. - } - destruct (rel_dec _ acc_tg (itag it_witness)); first contradiction. - (* Finally we have all the ingredients of the contradiction *) - rewrite /item_apply_access in GlobalSuccess. - destruct GlobalSuccess as [? GlobalSuccess]. - rewrite bind_Some in GlobalSuccess. - destruct GlobalSuccess as [tmp_perms [PermissionsApply Wrapper]]. - injection Wrapper; clear Wrapper; intros; subst. - rewrite /permissions_apply_range' in PermissionsApply. - pose proof (proj2 (mem_apply_range'_success_condition _ _ _) (mk_is_Some _ _ PermissionsApply)) - as PermissionApply. - specialize (PermissionApply l InRange). - unfold item_lookup in Hdis. - rewrite /maybe_non_children_only in PermissionApply. - rewrite /nonchildren_only /= in PermissionApply. - repeat rewrite if_fun_absorb_args in PermissionApply. - rewrite Tauto.if_same in PermissionApply. - rewrite /apply_access_perm /= in PermissionApply. - destruct PermissionApply as [tmp_lazy PermissionApply]. - rewrite bind_Some in PermissionApply. - destruct PermissionApply as [tmp_perm [ApplyAccessInner ValidateProt]]. - rewrite Hdis in ApplyAccessInner. - rewrite /apply_access_perm_inner in ApplyAccessInner. - case_match; discriminate. - * inversion DisWitnessPre as [HX DisWitness|lp HDis Hlookup HX]; simplify_eq. - 1: rewrite -DisWitness in HNonDis; done. - inversion Hlookup as [HX1 HX2|tg_w2 it_w2 x1 x2 Hcs2 Hlu2 Hprot2 Hperm2 Hlp]; simplify_eq. - 1: rewrite -HX // in HNonDis. - rewrite <- apply_access_success_condition in GlobalSuccess. - rewrite every_node_iff_every_lookup in GlobalSuccess. 2: { - intros tg0 Ex0. apply unique_lookup. apply GloballyUnique1. assumption. - } - specialize (GlobalSuccess _ _ Hlu2). - pose proof (tree_determined_specifies_tag _ _ _ (proj1 Hlu2) (proj2 Hlu2)) - as <-. - rewrite /rel_dec in RelWitness. - destruct decide as [HPC1|] in RelWitness; last done. clear RelWitness. - rewrite /rel_dec in AccRel. - destruct decide as [HPC2|] in AccRel; last done. clear AccRel. - rewrite /rel_dec decide_False in GlobalSuccess; last first. - { intros HH. exfalso. eapply cousins_have_disjoint_children. 4: exact Hcs2. - 5: exact HH. 4: eapply ParentChild_transitive; eassumption. - 1: done. all: eapply GloballyUnique1. 2: eapply Hlu2. eapply LookupWitness. } - rewrite decide_False in GlobalSuccess; last first. - { intros HH. rewrite /rel_dec in Hcs2. - destruct decide as [|HHH] in Hcs2; first done. - destruct decide as [|HHH2] in Hcs2; first done. - eapply HHH2. do 3 (eapply ParentChild_transitive; first done). by left. } - exfalso. rewrite /item_apply_access in GlobalSuccess. - rewrite is_Some_ignore_bind in GlobalSuccess. - eapply mem_apply_range'_success_condition in GlobalSuccess. 2: done. - rewrite maybe_non_children_only_no_effect // in GlobalSuccess. - rewrite /item_lookup in Hperm2. rewrite Hperm2 in GlobalSuccess. - rewrite bool_decide_true // in GlobalSuccess. - destruct kind; cbv in GlobalSuccess; by destruct GlobalSuccess. - + rewrite <- EqProt. - destruct (bool_decide (protector_is_active (iprot it1) C)) eqn:Heq; last first. - { rewrite Tg2 -Tg1 -SameRel AccRel. - rewrite /maybe_non_children_only /nonchildren_only. - repeat rewrite if_fun_absorb_args. - repeat case_match; first done. - all: rewrite /apply_access_perm /apply_access_perm_inner //=. - all: repeat case_match; done. } - rewrite Tg2 -Tg1 -SameRel AccRel. - rewrite /maybe_non_children_only /nonchildren_only. - repeat rewrite if_fun_absorb_args. - inversion Dis2 as [it_witness ? RelWitness LookupWitness DisWitnessPre]. - (* we are protected. this means we are not initalized by state_wf *) - assert (initialized (item_lookup it2 l) = PermLazy) as HH. - 1: inversion DisWitnessPre as [HX DisWitness|lp HX HDis Hlookup]; simplify_eq. - { specialize (ProtParentsNonDis witness_tg). eapply every_child_ParentChildIn in ProtParentsNonDis. - 2: done. 2: eapply GloballyUnique2, LookupWitness. 2: eapply LookupWitness. 2: eapply GloballyUnique2, Ex2. - 2: rewrite /rel_dec in RelWitness; by destruct (decide (ParentChildIn witness_tg (itag it1) tr2)). - setoid_rewrite every_node_eqv_universal in ProtParentsNonDis. - ospecialize (ProtParentsNonDis it2 _ _). - 1: eapply exists_determined_exists; eapply Ex2. 1: by eapply tree_lookup_correct_tag. - rewrite /item_protected_all_parents_not_disabled in ProtParentsNonDis. - ospecialize (ProtParentsNonDis l). destruct (initialized (item_lookup it2 l)); last done. - rewrite -EqProt -DisWitness in ProtParentsNonDis. ospecialize (ProtParentsNonDis _ _). - 1: done. 1: by eapply bool_decide_eq_true_1. 1: done. } - { specialize (ParentsMoreInit witness_tg). eapply every_child_ParentChildIn in ParentsMoreInit. - 2: done. 2: eapply GloballyUnique2, LookupWitness. 2: eapply LookupWitness. 2: eapply GloballyUnique2, Ex2. - 2: rewrite /rel_dec in RelWitness; by destruct (decide (ParentChildIn witness_tg (itag it1) tr2)). - setoid_rewrite every_node_eqv_universal in ParentsMoreInit. - ospecialize (ParentsMoreInit it2 _ _). - 1: eapply exists_determined_exists; eapply Ex2. 1: by eapply tree_lookup_correct_tag. - ospecialize (ParentsMoreInit l). destruct (initialized (item_lookup it2 l)); last done. - rewrite -Hlookup in ParentsMoreInit. ospecialize (ParentsMoreInit _). - 1: done. 1: done. } - all: rewrite /apply_access_perm /apply_access_perm_inner HH //=. - all: repeat case_match; done. - - (* Frozen in practice case. - Before we do the usual manipulations we make both the left and right access use - the same [rel_dec] so that the [maybe_non_children_only] case distinction works - on both simultaneously. *) - rewrite SameRel in Acc1. - edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]. - 2: by erewrite Heq. (* Noop case, easy. *) - rewrite Heq. - rewrite Tg1 -Tg2 Heq in Acc1. - destruct kind, (rel_dec tr2 _ _) eqn:Rel. - + (* Foreign read is allowed *) - unfold apply_access_perm, apply_access_perm_inner. - repeat (case_match; simpl; try auto). - + (* Child read is allowed *) - unfold apply_access_perm, apply_access_perm_inner. - repeat (case_match; simpl; try auto). - + (* Foreign write is allowed, except when there is a protector. - Once we eliminate all other cases we'll have to prove that the protector is inactive by - using the left tree in which the access suceeded. *) - unfold apply_access_perm, apply_access_perm_inner. - repeat (case_match; simpl; try auto). - (* Now we have a goal that is definitely not provable, but we have gained - a hypothesis [protector_is_active] in the context. We can derive a contradiction. *) - all: exfalso. - all: unfold apply_access_perm, apply_access_perm_inner in Acc1. - all: repeat (case_match; simpl in Acc1; try auto). - all: try (inversion Acc1; congruence). - (* We have all the elements of the contradiction, but a bit of rewriting is necessary - to get them in a shape that is obviously conflicting. - At that point there are two kinds of goals - - some where the protector is active only on one side, solve them using [EqProt], - - others whene [initialized] returns inconsistent results, solve them by - unifying the same [ini] everywhere. *) - all: repeat multimatch goal with - | H : bool_decide _ = true |- _ => pose proof (bool_decide_eq_true_1 _ H); clear H - | H : bool_decide _ = false |- _ => pose proof (bool_decide_eq_false_1 _ H); clear H - | H : context [ iprot _ ] |- _ => rewrite EqProt in H - | |- _ => try contradiction - end. - all: assert (initialized (item_lookup it1 l) = ini) as Ini1 by (rewrite -Lookup1; done). - all: simpl in *; congruence. - + (* Child write is necessarily UB due to the Frozen parent *) - exfalso. - specialize (Hrestrict eq_refl). subst d. - eapply frozen_in_practice_rejects_child_write. 4: exact GlobalSuccess. - * eassumption. - * eassumption. - * eassumption. - * eexists. rewrite SameRel. rewrite -Tg2. apply Rel. - - rewrite -SameRel Tg2 -Tg1 -EqProt. edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]; - erewrite Heq in Acc1; erewrite Heq; clear Heq. 2: done. - rewrite -Lookup1 in Acc1. destruct kind. - + destruct d; (inversion Hd as [P Hprot|P Hnoprot]; subst P p1 p2; - [ rewrite bool_decide_eq_false_2 // in Acc1|-* - | rewrite bool_decide_eq_true_2 // in Acc1|-*]). - all: destruct (rel_dec tr1 acc_tg (itag it1)), ini. - all: rewrite /apply_access_perm /apply_access_perm_inner /= in Acc1|-*; done. - + specialize (Hrestrict eq_refl). subst d. - inversion Hd as [P Hprot|P Hnoprot]; subst P p1 p2. - 1: rewrite bool_decide_eq_false_2 // in Acc1|-*. - 2: rewrite bool_decide_eq_true_2 // in Acc1|-*. - all: destruct (rel_dec tr1 acc_tg (itag it1)), ini. - all: rewrite /apply_access_perm /apply_access_perm_inner /= in Acc1|-*; done. - Qed. - - Lemma item_eq_up_to_C_allows_more_access (b:bool) - {d tr1 tr2 tg it1 it2 kind acc_tg range} - (Tg1 : itag it1 = tg) - (Tg2 : itag it2 = tg) - (UnqAcc : tree_unique acc_tg tr1) - (UnqAcc2 : tree_unique acc_tg tr2) - (Ex1 : tree_unique tg tr1) - (Ex2 : tree_lookup tr2 tg it2) - (SameRel : forall tg tg', rel_dec tr1 tg tg' = rel_dec tr2 tg tg') - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (ParentsMoreInit : parents_more_init tr2) - (GlobalSuccess : is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1)) - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (Hrestrict : kind = AccessWrite → d = Forwards) - : - item_eq_up_to_C tr1 tr2 tg d it1 it2 -> - is_Some (item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr1 acc_tg (itag it1)) range it1) -> - is_Some (item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr2 acc_tg (itag it2)) range it2). - Proof. - rewrite /item_apply_access /permissions_apply_range'. - rewrite is_Some_ignore_bind. - rewrite is_Some_ignore_bind. - intros EqC. - intro App1. - rewrite -mem_apply_range'_success_condition in App1. - rewrite -mem_apply_range'_success_condition. - intros l InRange. - specialize (App1 l InRange). - specialize (EqC l). - eapply (loc_eq_up_to_C_allows_more_access Tg1 Tg2 UnqAcc UnqAcc2 Ex1 Ex2 SameRel); done. - Qed. - - Lemma tree_equal_allows_more_access_maybe_nonchildren_only (b:bool) - {d tr1 tr2 kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (ParentsMoreInit : parents_more_init tr2) - (Hrestrict : kind = AccessWrite → d = Forwards) : - tree_equal d tr1 tr2 -> - tree_unique acc_tg tr1 -> - is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1) -> - is_Some (tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr2). - Proof. - intros Eq UnqAcc Acc1. - apply apply_access_success_condition. - pose proof (proj2 (apply_access_success_condition _ _ _ _ _) Acc1) as Every1. - (* Get it into a more usable form *) - rewrite every_node_iff_every_lookup in Every1. - 2: eapply tree_equal_implies_globally_unique_1; eassumption. - rewrite every_node_iff_every_lookup. - 2: eapply tree_equal_implies_globally_unique_2; eassumption. - (* And now we can unfold the definitions more *) - intros tg it Lookup2. - pose proof Eq as EqCopy. - destruct EqCopy as [ExIff [SameRel Lookup]]. - destruct (tree_equal_transfer_lookup_2 Eq Lookup2) as [it1 [Lookup1 EqC]]. - eapply (item_eq_up_to_C_allows_more_access b). - - erewrite tree_determined_specifies_tag. 2,3: eapply Lookup1. reflexivity. - - erewrite tree_determined_specifies_tag. 2,3: eapply Lookup2. reflexivity. - - apply UnqAcc. - - eapply GloballyUnique2. destruct Eq as (H1&H2&H3). eapply H1. by eapply unique_exists. - - apply GloballyUnique1. apply Lookup1. - - done. - - eassumption. - - eapply ProtParentsNonDis. - - done. - - apply Acc1. - - exact GloballyUnique1. - - exact GloballyUnique2. - - done. - - done. - - eapply Every1; eassumption. - Qed. - - Lemma tree_equal_allows_more_access - {d tr1 tr2 kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (ParentsMoreInit : parents_more_init tr2) - (Hrestrict : kind = AccessWrite → d = Forwards) : - tree_equal d tr1 tr2 -> - tree_unique acc_tg tr1 -> - is_Some (memory_access kind C acc_tg range tr1) -> - is_Some (memory_access kind C acc_tg range tr2). - Proof. - by eapply (tree_equal_allows_more_access_maybe_nonchildren_only false). - Qed. - - Lemma tree_equal_allows_more_access_nonchildren_only - {d tr1 tr2 kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (ParentsMoreInit : parents_more_init tr2) - (Hrestrict : kind = AccessWrite → d = Forwards) : - tree_equal d tr1 tr2 -> - tree_unique acc_tg tr1 -> - is_Some (memory_access_nonchildren_only kind C acc_tg range tr1) -> - is_Some (memory_access_nonchildren_only kind C acc_tg range tr2). - Proof. - by eapply (tree_equal_allows_more_access_maybe_nonchildren_only true). - Qed. - - Lemma memory_access_same_rel_dec - {tr tr' acc cids acc_tg range} b - : memory_access_maybe_nonchildren_only b acc cids acc_tg range tr = Some tr' -> - forall tg tg', rel_dec tr tg tg' = rel_dec tr' tg tg'. - Proof. eapply access_same_rel_dec. Qed. - - Lemma access_preserves_pseudo_conflicted_activable (b:bool) - {tr tg l kind acc_tg range tr'} : - pseudo_conflicted tr tg l ResActivable -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr' -> - pseudo_conflicted tr' tg l ResActivable. - Proof. - intros PseudoC Acc. - inversion PseudoC as [|tg_cous it_cous cous_rel [cous_ex cous_det] cous_prot cous_nondis cous_init]. - destruct (apply_access_spec_per_node cous_ex cous_det Acc) - as (cous' & cous'_spec & cous'_ex & cous'_det). - symmetry in cous'_spec. - rewrite bind_Some in cous'_spec. - destruct cous'_spec as (perms' & perms'_spec & cous'_build). - injection cous'_build; intros; subst; clear cous'_build. - pose proof (mem_apply_range'_spec _ _ l _ _ perms'_spec) as effect_at_l. - destruct (decide _). - + (* within range. Big case analysis incoming. *) - destruct effect_at_l as (perm' & perm'_lookup & perm'_spec). - edestruct (maybe_non_children_only_effect_or_nop b (apply_access_perm kind) (rel_dec tr acc_tg (itag it_cous))) as [Heff|Heff]. - all: rewrite Heff in perm'_spec. - 1: rewrite bind_Some in perm'_spec; - destruct perm'_spec as (perm & perm_apply_inner & perm'_spec); - rewrite bind_Some in perm'_spec; - destruct perm'_spec as (perm_validated & perm_check_prot & perm'_spec). - all: pose proof perm'_spec as [= <-]. - all: (econstructor; [ - erewrite <- access_same_rel_dec; eassumption - | done - | done - | .. ]). - * rewrite /item_lookup /= perm'_lookup /=. - rewrite /item_lookup in cous_init. - destruct (iperm it_cous !! l) eqn:it_cous_defined. - all: rewrite it_cous_defined !cous_init in perm_check_prot. - all: rewrite bool_decide_eq_true_2 in perm_check_prot; last assumption. - all: destruct perm; try discriminate. - all: injection perm_check_prot; intros; subst; congruence. - * rewrite /item_lookup /= perm'_lookup /=. - rewrite /item_lookup in cous_init. - destruct (iperm it_cous !! l) eqn:it_cous_defined; - rewrite it_cous_defined cous_init //=. - * rewrite /item_lookup /= perm'_lookup //. - * rewrite /item_lookup /= perm'_lookup //. - + (* out of range is a lot easier *) - econstructor. - * erewrite <- access_same_rel_dec; eassumption. - * split; eassumption. - * eassumption. - * rewrite /item_lookup /= effect_at_l. assumption. - * rewrite /item_lookup /= effect_at_l. assumption. - Qed. - - Lemma access_preserves_pseudo_conflicted (b:bool) - {tr tg l kind acc_tg range conf tr'} : - pseudo_conflicted tr tg l conf -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr' -> - pseudo_conflicted tr' tg l conf. - Proof. - intros Hpc Haccess. destruct conf. - 2: by eapply access_preserves_pseudo_conflicted_activable. - inversion Hpc; by econstructor. - Qed. - - Lemma access_preserves_pseudo_disabled lp pr (b:bool) - {tr tg l kind acc_tg range tr'} : - pseudo_disabled tr tg l lp pr -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr' -> - pseudo_disabled tr' tg l lp pr. - Proof. - intros PseudoC Acc. - inversion PseudoC as [|tg_cous it_cous X1 X2 cous_rel [cous_ex cous_det] cous_nondis cous_init Hextra]; simplify_eq. - 1: econstructor 1. - destruct (apply_access_spec_per_node cous_ex cous_det Acc) - as (cous' & cous'_spec & cous'_ex & cous'_det). - symmetry in cous'_spec. - rewrite bind_Some in cous'_spec. - destruct cous'_spec as (perms' & perms'_spec & cous'_build). - injection cous'_build; intros; subst; clear cous'_build. - pose proof (mem_apply_range'_spec _ _ l _ _ perms'_spec) as effect_at_l. - destruct (decide _); last first. - + (* out of range is a lot easier *) - econstructor 2. - * erewrite <- access_same_rel_dec; eassumption. - * split; eassumption. - * eassumption. - * rewrite /item_lookup /= effect_at_l. assumption. - * done. - + (* within range. Big case analysis incoming. *) - destruct effect_at_l as (perm' & perm'_lookup & perm'_spec). - rewrite /item_lookup in cous_init. rewrite cous_init in perm'_spec. - rewrite bool_decide_true in perm'_spec. 2: done. - destruct b, kind, rel_dec as [[]|] in perm'_spec; cbv in perm'_spec. - all: try discriminate perm'_spec. - all: injection perm'_spec as <-. - all: econstructor 2; - [ erewrite <- access_same_rel_dec; eassumption - | split; eassumption - | done - | rewrite /item_lookup perm'_lookup /= // - | done - ]. - Qed. - - Lemma tree_apply_access_preserves_protector - {tr tr' tg acc_tg kind range b it it'} - (Lookup : tree_lookup tr tg it) - (Lookup' : tree_lookup tr' tg it') - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : iprot it' = iprot it. - Proof. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it'' [Spec'' [Ex'' Det'']]]. - symmetry in Spec''. - destruct (item_apply_access_preserves_metadata it it'' Spec'') as [?[]]. - rewrite (tree_determined_unify (proj1 Lookup') (proj2 Lookup') Det''). - done. - Qed. - - Lemma disabled_tree_apply_access_irreversible - {tr tr' tg acc_tg kind range loc b it} - (Lookup : tree_lookup tr tg it) - (Dis : perm (item_lookup it loc) = Disabled) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : exists it', - tree_lookup tr' tg it' - /\ perm (item_lookup it' loc) = Disabled. - Proof. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it' [Spec' [Ex' Det']]]. - exists it'. - split; first done. - symmetry in Spec'. - rewrite bind_Some in Spec'. destruct Spec' as [tmp [PermsApp Build]]. - injection Build; intros; subst; clear Build. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsApp) as LocSpec. - destruct (decide _). - + destruct LocSpec as [val [LookupVal SpecVal]]. - rewrite /item_lookup LookupVal /=. - rewrite /maybe_non_children_only /nonchildren_only in SpecVal. - repeat case_match. - 1: { injection SpecVal; intros; subst; done. } - all: rewrite /apply_access_perm /apply_access_perm_inner /= in SpecVal. - all: rewrite Dis /= in SpecVal. - all: repeat case_match; simpl in *; try congruence. - all: injection SpecVal; intros; subst; simpl; done. - + rewrite /item_lookup /= LocSpec Dis //. - Qed. - - Lemma is_disabled_tree_apply_access_child - {tr tr' tg acc_tg kind range loc b it} - (Lookup : tree_lookup tr tg it) - (Dis : is_disabled tr tg loc (item_lookup it loc) (iprot it)) - (Cont : tree_contains acc_tg tr) - (Uni : wf_tree tr) - (Inside : range'_contains range loc) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : ¬ ParentChildIn tg acc_tg tr. - Proof. - intros HPC. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it' [Spec' [Ex' Det']]]. - symmetry in Spec'. - rewrite bind_Some in Spec'. destruct Spec' as [tmp [PermsApp Build]]. - injection Build; intros; subst; clear Build. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsApp) as LocSpec. - eapply tree_lookup_correct_tag in Lookup as HH; subst tg. - rewrite decide_True // in LocSpec. - destruct LocSpec as (v&Hv&HHv). - destruct (decide (perm (item_lookup it loc) = Disabled)) as [Hdis|Hnondis]. - { rewrite /rel_dec decide_True // in HHv. - rewrite maybe_non_children_only_no_effect // in HHv. - rewrite /apply_access_perm /apply_access_perm_inner /= Hdis in HHv. - by destruct kind. } - inversion Dis as [X1 Hlu X2|lp X1 Hdis Hlu X2]; simplify_eq. - 1: rewrite -Hlu in Hnondis; done. - inversion Hdis as [X1 X2 X3|tg_cs it_cs X1 X2 Hcs Hlucs Hprotcs Hppcs Hcsfoo X3 X4]; simplify_eq. - 1: rewrite -Hlu in Hnondis; done. - destruct (apply_access_spec_per_node (proj1 Hlucs) (proj2 Hlucs) Acc) as [itcs' [Speccs' Hlucs']]. - symmetry in Speccs'. - rewrite bind_Some in Speccs'. destruct Speccs' as [tmpcs [PermsAppcs [= <-]]]. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsAppcs) as LocSpeccs. - rewrite decide_True // in LocSpeccs. - destruct LocSpeccs as [valcs [Hvcs HHvcs]]. - rewrite /rel_dec in HHvcs. - eapply tree_lookup_correct_tag in Hlucs' as HH; subst tg_cs. - rewrite decide_False in HHvcs; last first. - { intros HnPCI1. eapply cousins_have_disjoint_children in Hcs. 5: done. 5: done. - 1: done. all: simpl; eapply Uni. 1: done. 1: apply Lookup. 1: eapply Hlucs. } - rewrite decide_False in HHvcs; last first. - { intros HnPCI1. - rewrite /rel_dec in Hcs. - destruct decide as [?|HNP2] in Hcs; first done. - destruct decide as [?|HNP3] in Hcs; first done. - eapply HNP3; simpl. eapply ParentChild_transitive. - 1: done. done. } - rewrite maybe_non_children_only_no_effect // in HHvcs. - rewrite bool_decide_true // in HHvcs. - rewrite /item_lookup in Hppcs. - rewrite Hppcs in HHvcs. destruct kind; done. - Qed. - - Lemma is_disabled_tree_apply_access_irreversible - {tr tr' tg acc_tg kind range loc b it} - (Lookup : tree_lookup tr tg it) - (Dis : is_disabled tr tg loc (item_lookup it loc) (iprot it)) - (Cont : tree_contains acc_tg tr) - (Uni : wf_tree tr) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : exists it', - tree_lookup tr' tg it' ∧ iprot it = iprot it' ∧ - is_disabled tr' tg loc (item_lookup it' loc) (iprot it'). - Proof. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it' [Spec' [Ex' Det']]]. - exists it'. - split; first done. - symmetry in Spec'. - rewrite bind_Some in Spec'. destruct Spec' as [tmp [PermsApp Build]]. - injection Build; intros; subst; clear Build. split; first done. - destruct (decide (perm (item_lookup it loc) = Disabled)) as [Hdis|Hnondis]. - { eapply disabled_tree_apply_access_irreversible in Hdis as (it'&Htr'&Hit'). 2-3: done. - eapply tree_determined_unify in Det'. 2: done. 2: apply Htr'. - destruct (item_lookup it' loc) as [[] pp] eqn:Hini; subst it'. - all: rewrite Hini. all: simpl in Hit'; subst pp. - 1: econstructor 1. 1: econstructor 2. econstructor 1. } - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsApp) as LocSpec. - inversion Dis as [X1 Hlu X2|lp X1 Hdis Hlu X2]; simplify_eq. - 1: rewrite -Hlu in Hnondis; done. - inversion Hdis as [X1 X2 X3|tg_cs it_cs X1 X2 Hcs Hlucs Hprotcs Hppcs Hcsfoo X3 X4]; simplify_eq. - 1: rewrite -Hlu in Hnondis; done. - destruct (apply_access_spec_per_node (proj1 Hlucs) (proj2 Hlucs) Acc) as [itcs' [Speccs' Hlucs']]. - symmetry in Speccs'. - rewrite bind_Some in Speccs'. destruct Speccs' as [tmpcs [PermsAppcs [= <-]]]. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsAppcs) as LocSpeccs. - destruct (decide _) as [In|Out]; last first. - + rewrite /item_lookup /= LocSpec. - rewrite /item_lookup in Hlu. rewrite -Hlu. - econstructor. eapply access_preserves_pseudo_disabled. 1: done. done. - + destruct LocSpec as [val [LookupVal SpecVal]]. - destruct LocSpeccs as [valcs [LookupValcs SpecValcs]]. - rewrite /rel_dec in SpecVal. - eapply tree_lookup_correct_tag in Lookup as HH; subst tg. - eapply tree_lookup_correct_tag in Hlucs' as HH; subst tg_cs. - rewrite decide_False in SpecVal. - 2: { eapply is_disabled_tree_apply_access_child. 6: done. 2: done. all: done. } - edestruct maybe_non_children_only_effect_or_nop as [Heff|Heff]; - erewrite Heff in SpecVal; clear Heff. - 2: { injection SpecVal as <-. simpl. - rewrite /item_lookup /= in Hlu|-*. - rewrite LookupVal /= -Hlu. - econstructor 2. eapply access_preserves_pseudo_disabled; last done. - done. } - rewrite /item_lookup in Hlu. rewrite -Hlu in SpecVal. - rewrite /apply_access_perm /apply_access_perm_inner most_init_comm /= in SpecVal. - destruct kind, bool_decide eqn:Hbdc, lp as [[]| | | |] eqn:Hpm in SpecVal. - all: simpl in SpecVal. all: try discriminate SpecVal. - all: injection SpecVal as <-. - all: rewrite /= /item_lookup /= LookupVal /=. - all: econstructor 2. - all: eapply access_preserves_pseudo_disabled; last done. - all: econstructor; [exact Hcs|exact Hlucs|exact Hprotcs|exact Hppcs|]. - all: intros [=]. - all: subst lp; eapply Hcsfoo; done. - Qed. - - Lemma create_child_irreversible - {tr tr' tg tg_old tg_new it pk im rk cid} - (Lookup : tree_lookup tr tg it) - (Fresh : tg_new ≠tg) - (Ins : create_child C tg_old tg_new pk im rk cid tr = Some tr') - : tree_lookup tr' tg it. - Proof. - pose proof Ins as (x&<-%new_item_has_tag&[= <-])%bind_Some. - destruct Lookup as [Ex Det]. split. - - apply insert_preserves_exists; assumption. - - apply insert_true_preserves_every; last assumption. - intro SameTg. done. - Qed. - - Definition becomes_frozen (kind : access_kind) (range : Z * nat) (loc : Z) (b:bool) tr acc_tg it_tg: Prop := - if decide (range'_contains range loc) then kind = AccessRead ∨ (∃ k, b = true ∧ rel_dec tr acc_tg it_tg = Foreign (Parent k)) else True. - Definition becomes_disabled (kind : access_kind) (range : Z * nat) (loc : Z) (b:bool) tr acc_tg it_tg: Prop := - if decide (range'_contains range loc) then kind = AccessWrite ∧ (∃ f, rel_dec tr acc_tg it_tg = Foreign f ∧ ∀ p, f = Parent p → b = false) else False. - - Lemma becomes_not_both kind range loc b tr acc_tg it_tg : - becomes_frozen kind range loc b tr acc_tg it_tg → - becomes_disabled kind range loc b tr acc_tg it_tg → - False. - Proof. - intros H1 H2. - rewrite /becomes_frozen /becomes_disabled in H1,H2. - destruct decide. 2: done. - destruct H2 as (->&f&Hff&Hfb). - destruct H1 as [[=]|(k&->&Hk)]. - rewrite Hk in Hff. simplify_eq. - by specialize (Hfb _ eq_refl). - Qed. - - Lemma frozen_tree_apply_access_irreversible - {tr tr' tg acc_tg kind range loc b it} - (Lookup : tree_lookup tr tg it) - (Frz : (item_lookup it loc).(perm) = Frozen) - (Ini : (item_lookup it loc).(initialized) = PermInit) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : exists it', - tree_lookup tr' tg it' - /\ let k := (item_lookup it' loc) in let bf := becomes_frozen kind range loc b tr acc_tg (itag it) in let bd := becomes_disabled kind range loc b tr acc_tg (itag it) in - k.(initialized) = PermInit - /\ (k.(perm) = Frozen ∧ bf ∨ (k.(perm) = Disabled ∧ bd ∧ ¬ protector_is_active it'.(iprot) C)). - Proof. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it' [Spec' [Ex' Det']]]. - exists it'. - split; first done. - symmetry in Spec'. - rewrite bind_Some in Spec'. destruct Spec' as [tmp [PermsApp Build]]. - intros k bf bd. - injection Build; intros; subst; clear Build. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsApp) as LocSpec. subst bf bd. rewrite /becomes_frozen /becomes_disabled. - destruct (decide _); last first. - + subst k. rewrite /item_lookup /= LocSpec Frz Ini //. split; first done. by left. - + destruct LocSpec as [val [LookupVal SpecVal]]. subst k. - rewrite /item_lookup LookupVal /=. - rewrite /maybe_non_children_only /nonchildren_only in SpecVal. - repeat case_match. - 1: { injection SpecVal; intros; subst; split; first done. left. split; first done. eauto. } - all: rewrite /apply_access_perm /apply_access_perm_inner /= in SpecVal. - all: rewrite Frz /= Ini /= in SpecVal. - all: repeat case_match; simpl in *; try congruence. - all: injection SpecVal; intros; subst; simpl; split; first done. - all: first [ left; split; first done; eauto | right; split; first done; split ]. - 2, 4: by eapply bool_decide_eq_false_1. - all: split; first done. - all: eexists; split; first done. - 1: intros ? [=]. done. - Qed. - - Lemma parent_has_perm_similarly_disabled_after_access - {pp tr tr' tg acc_tg kind range loc b it} - (Lookup : tree_lookup tr tg it) - (Frz : (item_lookup it loc).(perm) = pp) - (nRIM : pp ≠ReservedIM) - (Ini : (item_lookup it loc).(initialized) = PermInit) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : exists it', - tree_lookup tr' tg it' - /\ let k := (item_lookup it' loc) in let bd := becomes_disabled kind range loc b tr acc_tg (itag it) in - k.(initialized) = PermInit - /\ (bd → (k.(perm) = Disabled ∧ ¬ protector_is_active it'.(iprot) C)). - Proof. - destruct (apply_access_spec_per_node (proj1 Lookup) (proj2 Lookup) Acc) as [it' [Spec' [Ex' Det']]]. - exists it'. - split; first done. - symmetry in Spec'. - rewrite bind_Some in Spec'. destruct Spec' as [tmp [PermsApp Build]]. - intros k bd. - injection Build; intros; subst; clear Build. - pose proof (mem_apply_range'_spec _ _ loc _ _ PermsApp) as LocSpec. subst bd. rewrite /becomes_disabled. - destruct (decide _); last first. - + subst k. rewrite /item_lookup /= LocSpec Ini //. - + destruct LocSpec as [val [LookupVal SpecVal]]. subst k. - rewrite /item_lookup LookupVal /=. - rewrite /maybe_non_children_only /nonchildren_only in SpecVal. - repeat case_match. - 1: { injection SpecVal; intros; subst; split; first done. intros (->&f&[= <-]&HH). by specialize (HH _ eq_refl). } - all: rewrite /apply_access_perm /apply_access_perm_inner /= in SpecVal. - all: rewrite /= Ini /= in SpecVal. - all: repeat case_match; simpl in *; try congruence. - all: injection SpecVal; intros; subst; simpl; split; first done. - all: intros (Heq1&Hf&Heq2&HHf); simplify_eq. - all: split; last try by eapply bool_decide_eq_false_1. - all: done. - Qed. - - Lemma disabled_in_practice_tree_apply_access_irreversible - {tr tr' tg acc_tg kind range witness loc b} - (Dis : disabled_in_practice tr tg witness loc) - (Cont : tree_contains acc_tg tr) - (Uni : wf_tree tr) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : disabled_in_practice tr' tg witness loc. - Proof. - inversion Dis as [?? Rel Lookup Perm]. - destruct (is_disabled_tree_apply_access_irreversible Lookup Perm Cont Uni Acc) as [it' [Lookup' Perm']]. - econstructor. - + erewrite <- access_same_rel_dec; eassumption. - + apply Lookup'. - + apply Perm'. - Qed. - - Lemma frozen_in_practice_tree_apply_access_irreversible - {tr tr' tg acc_tg kind range witness loc b} - (Frz : frozen_in_practice tr tg witness loc) - (Cont : tree_contains acc_tg tr) - (Uni : wf_tree tr) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : let bf := becomes_frozen kind range loc b tr acc_tg witness in - let bd := becomes_disabled kind range loc b tr acc_tg witness in - (frozen_in_practice tr' tg witness loc ∧ bf) ∨ (parent_has_perm Disabled tr' tg witness loc ∧ bd). - Proof. - inversion Frz as [it_witness incl Rel Lookup Perm Init]. - assert (itag it_witness = witness) as <- by by eapply tree_lookup_correct_tag. - destruct (frozen_tree_apply_access_irreversible Lookup Perm Init Acc) as [it' [Lookup' [Init' [[Perm' BF]|[Perm' [BF NoProt]]]]]]. - - left. split; last done. econstructor. - + erewrite <- access_same_rel_dec; eassumption. - + apply Lookup'. - + apply Perm'. - + apply Init'. - - right. split; last done. econstructor. - + erewrite <- access_same_rel_dec; eassumption. - + apply Lookup'. - + destruct (item_lookup it' loc) as [lp pp]; simpl in Init',Perm'; subst. done. - + destruct (item_lookup it' loc) as [lp pp]; simpl in Init',Perm'; subst. done. - Qed. - - Lemma parent_has_disabled_perm_is_pseudo_disabled tr tg witness loc : - parent_has_perm Disabled tr tg witness loc → - disabled_in_practice tr tg witness loc. - Proof. - inversion 1 as [it incl H0 H1 H2 H3]; simplify_eq. - econstructor. 1-2: done. - destruct (item_lookup it loc); simpl in H2,H3; simplify_eq. - econstructor 1. - Qed. - - Lemma parent_has_perm_similarly_disabled - {p tr tr' tg acc_tg kind range witness loc b} - (Frz : parent_has_perm p tr tg witness loc) - (nRIM : p ≠ReservedIM) - (Cont : tree_contains acc_tg tr) - (Uni : wf_tree tr) - (Acc : tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr = Some tr') - : let bd := becomes_disabled kind range loc b tr acc_tg witness in - bd → parent_has_perm Disabled tr' tg witness loc. - Proof. - inversion Frz as [it_witness incl Rel Lookup Perm Init]. - assert (itag it_witness = witness) as <- by by eapply tree_lookup_correct_tag. - destruct (parent_has_perm_similarly_disabled_after_access Lookup Perm nRIM Init Acc) as [it' [Lookup' [Init' Perm']]]. - intros bd. subst bd. intros Hbd. specialize (Perm' Hbd) as (Hd&Hnoprot). - econstructor. - + erewrite <- access_same_rel_dec; eassumption. - + apply Lookup'. - + destruct (item_lookup it' loc) as [lp pp]; simpl in Init',Hd; subst. done. - + destruct (item_lookup it' loc) as [lp pp]; simpl in Init',Hd; subst. done. - Qed. - - Lemma if_same_guard_equal - {P Q : Prop} {T} {x y x' y' : T} `{Decision P} `{Decision Q} - (Iff : P <-> Q) - (Ex : x = x') - (Ey : y = y') - : (if decide P then x else y) = (if decide Q then x' else y'). - Proof. - repeat destruct (decide _); tauto. - Qed. - - Lemma disabled_in_practice_create_child_irreversible - {tr tr' tg tg_old tg_new pk im rk cid witness loc} - (Ne : tg_new ≠tg) - (Ne' : tg_new ≠witness) - (Nc : ¬ tree_contains tg_new tr) - (Dis : disabled_in_practice tr tg witness loc) - (Ins : create_child C tg_old tg_new pk im rk cid tr = Some tr') - : disabled_in_practice tr' tg witness loc. - Proof. - inversion Dis as [it_witness ? Rel Lookup Perm]. - econstructor. - - erewrite <-create_child_same_rel_dec. 1: exact Rel. 3: done. 1-2: done. - - eapply create_child_irreversible. - 1: done. 2: done. done. - - inversion Perm as [|lp X H1 H2 X2]; simplify_eq. 1: econstructor 1. - econstructor 2. inversion H1 as [|tgcs itcs X1 X2 H1' H2' H3 H4 H5 X3 X4]; simplify_eq. 1: econstructor 1. - destruct (decide (tgcs = tg_new)) as [->|Hne]. - { exfalso. eapply Nc, H2'. } - econstructor 2. - + erewrite <-create_child_same_rel_dec. 1: exact H1'. 3: done. 1-2: done. - + eapply create_child_irreversible. 1: exact H2'. 2: done. done. - + done. - + done. - + done. - Qed. - - Lemma frozen_in_practice_create_child_irreversible - {tr tr' tg tg_old tg_new pk im rk cid witness loc} - (Ne : tg_new ≠tg) - (Ne' : tg_new ≠witness) - (Frz : frozen_in_practice tr tg witness loc) - (Ins : create_child C tg_old tg_new pk im rk cid tr = Some tr') - : frozen_in_practice tr' tg witness loc. - Proof. - inversion Frz as [it_witness ? Rel Lookup Perm Ini]. - opose proof (create_child_irreversible Lookup Ne' Ins) as Lookup'. - econstructor. - + erewrite <- create_child_same_rel_dec; first eassumption. - - eassumption. - - eassumption. - - eassumption. - + apply Lookup'. - + done. - + done. - Qed. - - Lemma most_init_comm {i i'} : - most_init i i' = most_init i' i. - Proof. - unfold most_init. - repeat case_match; reflexivity. - Qed. - - Lemma most_init_noop {i} : - most_init i PermLazy = i. - Proof. - unfold most_init. - case_match; reflexivity. - Qed. - - Lemma most_init_absorb {i} : - most_init i PermInit = PermInit. - Proof. - unfold most_init. - case_match; reflexivity. - Qed. - - Lemma trees_equal_find_equal_tag_protected_initialized_not_disabled d trs1 trs2 it1 tg blk off: - each_tree_protected_parents_not_disabled C trs2 → - wf_trees trs2 → - trees_equal d trs1 trs2 → - trees_lookup trs1 blk tg it1 → - (initialized (item_lookup it1 off) = PermInit → perm (item_lookup it1 off) ≠Disabled) → - protector_is_active it1.(iprot) C → - ∃ it2, trees_lookup trs2 blk tg it2 ∧ - (initialized (item_lookup it2 off) = PermInit → perm (item_lookup it2 off) ≠Disabled) ∧ - protector_is_active it2.(iprot) C. - Proof. - intros Heach Hwf Heq (tr1&Htr1&Hit) Hperm Hactive. - specialize (Heq blk). rewrite Htr1 in Heq. inversion Heq as [x tr2 Heq' Hx Htr2|]. subst x. - destruct Heq' as (Heq1&Heq2&Heq3). - pose proof Hit as (Hitin&Hitdet). - specialize (Heq3 _ Hitin) as (it1'&it2&Hit1'&Hit2&Heqit). - assert (it1 = it1') as <-. - { eapply tree_determined_unify. 2: done. 1: done. apply Hit1'. } - exists it2. specialize (Heqit off) as (Hprotit&Hlocit). - split. 1: exists tr2; done. - rewrite -Hprotit. inversion Hlocit as [|e c1 c2 H H1 H2 H3 H4| | | | |p1 p2 ini H]; simplify_eq. - - done. - - rewrite -!H3 /= in Hperm. simpl. done. - - exfalso. done. - - done. - - split; last done. intros Hinit Hdis. - ospecialize (Heach _ _ _ tg). 1: symmetry; exact Htr2. - eapply every_child_ParentChildIn in Heach. 2: by eapply Hwf. 2,4: eapply Hwf; first done; eapply Hit2. - 2: eapply Hit2. 2: by left. - rewrite every_node_eqv_universal in Heach. ospecialize (Heach it2 _ _ off _ _ Hdis). - 1: eapply exists_determined_exists; eapply Hit2. 1: by eapply tree_lookup_correct_tag. - 1: done. 1: by rewrite -Hprotit. done. - - split; last done. simpl. done. - - split; last done. simpl. intros ->. destruct d; by inversion H. - Qed. - - Lemma tree_lookup_IsTag tr tg it : tree_lookup tr tg it → IsTag tg it. - Proof. - intros (H1 & H2). - eapply exists_node_eqv_existential in H1 as (it2 & Hit2 & Histag). - eapply every_node_eqv_universal in H2; last done. - by rewrite -H2. - Qed. - - Lemma tree_lookup_unique tr tg it1 it2 : tree_lookup tr tg it1 → tree_lookup tr tg it2 → it1 = it2. - Proof. - intros Hlu (H1 & H2). - eapply every_node_eqv_universal in H2; first apply H2. - 1: by eapply tree_lookup_IsTag. - eapply exists_determined_exists; first done. - apply Hlu. - Qed. - - Lemma tree_equal_transfer_item_non_disabled d tr1 tr2 tg it off : - protected_parents_not_disabled C tr1 → - no_active_cousins C tr1 → - (∀ tg, tree_contains tg tr1 → tree_unique tg tr1) → - tree_equal d tr1 tr2 → - tree_lookup tr1 tg it → - protector_is_active (iprot it) C ∧ perm (item_lookup it off) ≠Disabled ∧ initialized (item_lookup it off) = PermInit → - ∃ it2, tree_lookup tr2 tg it2 ∧ protector_is_active (iprot it2) C ∧ perm (item_lookup it2 off) ≠Disabled ∧ initialized (item_lookup it2 off) = PermInit. - Proof. - intros Hpnd Hnac Hunq (He1&He2&He3) Hlu (Hprot&Hndis&Hini). - destruct (He3 tg) as (it1&it2&Hlu1&Hlu2&Heq). - 1: eapply Hlu. - assert (it = it1) as -> by by eapply tree_lookup_unique. - exists it2. specialize (Heq off) as (Hproteq&Hiteq). split; first done. - split. 1: by rewrite -Hproteq. - inversion Hiteq as [pp1|ini1 confl1 confl2 HprotX HP1 HP2 Heq1 Heq2|ini1 confl1 confl2 HnoProt|p1 p2 HP1 HP2 Heq1 Heq2|wit_tg lp1 lp2 Hdip1 Hdip2 HiniX Heq1 Heq2|ini1 confl1 confl2 wit_tg HF Heq1 Heq2|p1 p2 ini Hd Heq1 Heq2]; simplify_eq. - - done. - - split; first done. rewrite -Heq1 /= in Hini. rewrite /= Hini //. - - rewrite -Heq1 in Hini. done. - - exfalso. - inversion Hdip1 as [itw p Hreldec Hluw Hdisw]. - rewrite /rel_dec in Hreldec. destruct decide; last done. - eapply tree_lookup_correct_tag in Hlu as HH. subst tg. - specialize (Hpnd wit_tg). eapply every_child_ParentChildIn in Hpnd. - 2: eapply Hunq. 2: eapply Hunq, Hluw. 2: eapply Hluw. 2: eapply Hunq, Hlu. - 2: done. - eapply every_node_eqv_universal in Hpnd. - 2: { eapply tree_lookup_to_exists_node. eapply Hlu. } - inversion Hdisw as [X1 HH X2|pp X2 Hdis Hlazy X5]; simplify_eq. - { unshelve eapply (Hpnd _ off); [done..|by rewrite -HH]. } - inversion Hdis as [X1 HH X2|tgcs itcs lp X1 Hcs Hlucs Hprotcs Hactcs HH X2 X3]; simplify_eq. - { unshelve eapply (Hpnd _ off). 1-3: done. rewrite -Hlazy. done. } - eapply Hnac. 2: eapply Hlucs. 1: eapply Hlu. 3: by erewrite Hactcs. - 2: right; split; done. - eapply child_of_this_is_foreign_for_cousin. 4: exact Hcs. - 1-3: eapply Hunq. 1: eapply Hluw. 1: eapply Hlucs. 1: eapply Hlu. - rewrite /rel_dec decide_True //. - - split; first done. rewrite -Heq1 /= in Hini. rewrite /= Hini //. - - rewrite -Heq1 /= in Hini Hndis. simplify_eq. split; last done. - simpl. destruct d; inversion Hd; done. - Qed. - - Lemma tree_equal_transfer_pseudo_conflicted d tr1 tr2 tg off confl : - protected_parents_not_disabled C tr1 → - no_active_cousins C tr1 → - (∀ tg, tree_contains tg tr1 → tree_unique tg tr1) → - tree_equal d tr1 tr2 → - pseudo_conflicted tr1 tg off confl → - pseudo_conflicted tr2 tg off confl. - Proof. - intros Hpnd Hnac Hunq (HH1&HH2&HH3) Hconfl. - inversion Hconfl as [|tg_cs it_cs Hcs Hlu Hprot Hperm Hini]; simplify_eq. - - econstructor 1. - - edestruct tree_equal_transfer_item_non_disabled as (it2&Hit2&Hprot2&Hndis2&Hini2). - 1: exact Hpnd. 1: exact Hnac. 1: exact Hunq. 1: split; done. 1: exact Hlu. - 1: split; done. - econstructor 2. 1: by erewrite <- HH2. 1: exact Hit2. - all: done. - Qed. - - Global Instance pseudo_disabled_dec tr tg off pp oprot : Decision (pseudo_disabled tr tg off pp oprot). - Proof. - destruct (decide (pp = Disabled)) as [->|Hne]. - 1: left; econstructor 1. - pose (P it_cs := let tg_cs := itag it_cs in - rel_dec tr tg tg_cs = Foreign Cousin ∧ - tree_item_determined tg_cs it_cs tr ∧ - protector_is_active (iprot it_cs) C ∧ - item_lookup it_cs off = mkPerm PermInit Active ∧ - match pp with ReservedIM => False | _ => True end). - assert (∀ it, Decision (P it)) as DecP. - { intros it. - rewrite /P. - do 4 (eapply and_dec; first eapply _). - destruct pp. - all: eapply _. } - destruct (decide (exists_node P tr)) as [HP|HnP]. - - left. eapply exists_node_eqv_existential in HP as (it&Htgit&H1&H2&H3&H4&H5). - econstructor 2. - 1: exact H1. 1: split. 2: exact H2. - 1: eapply exists_node_eqv_existential; exists it; done. - 1: done. 1: done. - 1: intros ->. done. - - right. intros Hdis. - induction Hdis as [|tg_cs it_cs lp Hlp H1 H2 H3 H4 H5]; first done. - eapply HnP. eapply exists_node_eqv_existential. - exists it_cs. split. 1: eapply tree_lookup_to_exists_node; done. - assert (itag it_cs = tg_cs) as <- by by eapply tree_lookup_correct_tag. - split; first done. - split; first eapply H2. - split; first done. - split; first done. - destruct lp as [| | | |]; try done. - Defined. - - Global Instance is_disabled_dec tr tg off lp oprot : Decision (is_disabled tr tg off lp oprot). - Proof. - destruct (decide (lp = mkPerm PermInit Disabled)) as [->|Hne]. - 1: left; econstructor 1. - destruct lp as [[] pp]. - 1: { right. intros HH. inversion HH. subst pp. done. } - destruct (decide (pseudo_disabled tr tg off pp oprot)) as [Hpd|Hnpd]. - 1: left; econstructor 2; done. - right. - intros HH. inversion HH; simplify_eq. - Qed. - - Lemma exists_node_to_tree_lookup tr itm - (GloballyUnique : forall tg, tree_contains tg tr -> tree_unique tg tr) : - exists_node (eq itm) tr → - tree_lookup tr (itag itm) itm. - Proof. - intros Hexi. assert (tree_contains (itag itm) tr) as Hcontain. - - eapply exists_node_increasing; first done. - eapply every_node_eqv_universal; intros ? _ <-. done. - - split; first done. - eapply GloballyUnique, unique_lookup in Hcontain as (it2 & Hit2). - enough (itm = it2) by by subst itm. - eapply every_node_eqv_universal in Hit2; first eapply Hit2. - all: done. - Qed. - - Lemma trees_equal_decide_disabled_in_practice tr tg off : - (∀ tg, tree_contains tg tr → tree_unique tg tr) → - tree_contains tg tr → - (∃ tgp itp, tree_lookup tr tgp itp ∧ is_disabled tr tgp off (item_lookup itp off) (iprot itp) ∧ ParentChildIn tgp tg tr ∧ - ∀ tgpp itpp, tree_lookup tr tgpp itpp → StrictParentChildIn tgpp tgp tr → ¬ is_disabled tr tgpp off (item_lookup itpp off) (iprot itpp)) - + (∀ tgp itp, tree_lookup tr tgp itp → ParentChildIn tgp tg tr → ¬ is_disabled tr tgp off (item_lookup itp off) (iprot itp)). - Proof. - intros Hunq H. - assert (Decision (exists_node (λ it, is_disabled tr (itag it) off (item_lookup it off) (iprot it) ∧ ParentChildIn (itag it) tg tr) tr)) as Hdec. - { eapply exists_node_dec. intros itx. eapply and_dec. 2: by eapply ParentChildIn_dec. apply _. } - destruct Hdec as [Hleft|Hright]. - - left. - edestruct (find_highest_parent_with_property (λ x, is_disabled tr (itag x) off (item_lookup x off) (iprot x) ∧ ParentChildIn (itag x) tg tr)) as (tgpp&Htgpp&Hppp). - { intros x. eapply and_dec. 2: by eapply ParentChildIn_dec. apply _. } - { done. } - { done. } - eapply exists_node_eqv_existential in Htgpp. destruct Htgpp as (itpp&Hitpp&(HHitpp1&HHitpp2)&<-). - eapply exists_node_to_tree_lookup in Hitpp. 2: done. - exists (itag itpp), itpp. do 3 (split; first done). - intros tgppp itppp Hitppp HSPppp Hdis. - eapply Hppp. 2: exact HSPppp. - eapply tree_lookup_correct_tag in Hitppp as Htg. subst tgppp. - eapply exists_node_eqv_existential. exists itppp. - split. 2: split_and!; try done. 1: by eapply tree_lookup_to_exists_node. - eapply ParentChild_transitive; [|exact HHitpp2]; right; done. - - right. intros tgp itp Hlu HPC Hdis. eapply tree_lookup_correct_tag in Hlu as Htg; subst tgp. - eapply Hright. eapply exists_node_eqv_existential. - eexists. split. 1: eapply tree_lookup_to_exists_node, Hlu. split; done. - Qed. - - Lemma item_eq_up_to_C_same_iprot d tr1 tr2 tg it1 it2 : - item_eq_up_to_C tr1 tr2 tg d it1 it2 → - it1.(iprot) = it2.(iprot). - Proof. - intros H. specialize (H 0). inversion H. done. - Qed. - - Lemma perm_eq_up_to_C_same_init d tr1 tr2 tg off prot lp1 lp2 : - perm_eq_up_to_C tr1 tr2 tg off prot d lp1 lp2 → - initialized lp1 = initialized lp2. - Proof. - intros H. try by inversion H. - Qed. - - Lemma parents_not_disabled_child_not_active tr tg1 tg2 it1 it2 off - (Hwf : wf_tree tr) - (HPP : parents_more_active tr) : - tree_lookup tr tg1 it1 → - tree_lookup tr tg2 it2 → - ParentChildIn tg1 tg2 tr → - perm (item_lookup it1 off) = Disabled → - perm (item_lookup it2 off) = Active → - False. - Proof. - intros Hl1 Hl2 HPC Hp1 Hp2. - specialize (HPP tg1). eapply every_child_ParentChildIn in HPP. - 2: done. 2, 4: eapply Hwf. 2,4: eapply Hl1. 2: eapply Hl2. 2: done. - assert (tg1 = itag it1) as -> by by eapply tree_lookup_correct_tag in Hl1. - assert (tg2 = itag it2) as -> by by eapply tree_lookup_correct_tag in Hl2. - eapply every_node_eqv_universal in HPP. - 2: eapply tree_lookup_to_exists_node, Hl2. - ospecialize (HPP _ _ Hp2). 1: done. congruence. - Qed. - - Lemma disabled_in_practice_not_active tr tg1 tg2 it off - (Hwf : wf_tree tr) - (HPP : parents_more_active tr) - (HNC : no_active_cousins C tr) : - tree_lookup tr tg2 it → - perm (item_lookup it off) = Active → - disabled_in_practice tr tg2 tg1 off → - False. - Proof. - intros Hl1 Hact [it_witness incl H1 H2 H3]. - destruct (decide (perm (item_lookup it_witness off) = Disabled)) as [Hdis|Hnondis]. - + eapply parents_not_disabled_child_not_active. 1: exact Hwf. 1: done. 4: exact Hdis. 4: exact Hact. - 1-2: done. - rewrite /rel_dec in H1. destruct decide; done. - + inversion H3 as [X1 X2 X3|lp X HH1 HH2 X2]; simplify_eq. - { rewrite -X2 in Hnondis. done. } - inversion HH1 as [|tgcs itcs X1 X2 H1' H2' H3' H4 H5 X3 X4]; simplify_eq. - { rewrite -HH2 in Hnondis. done. } - eapply HNC. 1: exact H2'. 1: exact Hl1. 3: exact Hact. 2: right; split; first done. - 2: by rewrite H4. - rewrite /rel_dec in H1|-*. - destruct decide as [HPC1|] in H1; last done. clear H1. - rewrite decide_False; last first. - { intros HPC2. rewrite /rel_dec in H1'. - destruct decide in H1'; try done. - rewrite decide_True // in H1'. - eapply ParentChild_transitive. 1: exact HPC1. done. } - rewrite decide_False //. - intros HPC2. - eapply cousins_have_disjoint_children. 4: exact H1'. 4: exact HPC1. 4: done. - all: eapply Hwf. 1: eapply Hl1. 1: eapply H2. 1: eapply H2'. - Qed. - - Lemma tree_equal_transfer_pseudo_disabled {d tr tr2 tgcld off lp pp} : - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr2 → - no_active_cousins C tr2 → - pseudo_disabled tr2 tgcld off lp pp → - tree_equal d tr tr2 → pseudo_disabled tr tgcld off lp pp. - Proof. - intros Hunq Hwf1 Hwf2 HH (He1&He2&He3). - induction HH as [|tg_cs it_cs lp prot H1 H2 H3 H4 H5]. - 1: econstructor 1. - edestruct He3 as (it_cs1&X&Hit_cs1&HX&Hiteq). - 1: eapply He1, H2. - assert (X = it_cs) as -> by by eapply tree_lookup_unique. - specialize (Hiteq off) as (Hprot&Hiteq). - econstructor 2. 2: exact Hit_cs1. - 1: by rewrite He2. - 1: rewrite Hprot //. - 2: done. - rewrite H4 in Hiteq. - inversion Hiteq as [| | | | | |p1 p2 ini Hd]; simplify_eq. - - congruence. - - exfalso. eapply disabled_in_practice_not_active. - 5: erewrite H4; done. - 4: done. 1: done. 3: eassumption. all: done. - - rewrite -Hprot in H3. f_equal. - destruct d; inversion Hd; done. - Qed. - - Lemma transfer_pseudo_disabled_notimm p1 p2 tr tg off pp : - pseudo_disabled tr tg off p1 pp → - p2 ≠ReservedIM → p1 ≠Disabled → - pseudo_disabled tr tg off p2 pp. - Proof. - intros H Hne1 Hne2. - inversion H as [|X1 X2 X3 X4 X5 X6 X7 X8 X9]. 1: done. econstructor 2. - 1-4: done. done. - Qed. - - Lemma conflicted_transfer_pseudo_disabled c1 c2 tr tg off pp : - pseudo_disabled tr tg off (Reserved c1) pp → - pseudo_disabled tr tg off (Reserved c2) pp. - Proof. - intros HH. eapply transfer_pseudo_disabled_notimm. 1: done. all: done. - Qed. - - Lemma tree_equal_transfer_is_disabled {d tr tr2 tgcld off lp pp} : - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr2 → - no_active_cousins C tr2 → - is_disabled tr2 tgcld off lp pp → - tree_equal d tr tr2 → is_disabled tr tgcld off lp pp. - Proof. - intros Hunq ?? Hdis Heq. - induction Hdis as [|lp prot HH]. - 1: econstructor 1. - econstructor 2. - by eapply tree_equal_transfer_pseudo_disabled. - Qed. - - - Lemma trees_equal_transfer_disabled_in_practice_many {tr2 tgpar tgcld off} : - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr2 → - no_active_cousins C tr2 → - disabled_in_practice tr2 tgcld tgpar off → - ∃ tgpar', - disabled_in_practice tr2 tgcld tgpar' off ∧ - ∀ d tr', tree_equal d tr2 tr' → disabled_in_practice tr' tgcld tgpar' off. - Proof. - intros Hunq1 Hwf1 Hwf2 Hdip. - inversion Hdip as [itw incl Hrel Hlu Hperm]. - rewrite /rel_dec in Hrel. destruct decide as [HPCo|?]; try done. - destruct (trees_equal_decide_disabled_in_practice tr2 tgcld off) as [(tgp&itp&Hlup&Hdisp&HPC&Hothers)|HR]. - 1: done. - { eapply contains_child. 1: done. eapply Hlu. } - 2: { exfalso. eapply HR. 1: exact Hlu. 1: done. done. } - exists tgp. split_and!. - { econstructor. 2: exact Hlup. 2: done. rewrite /rel_dec decide_True //. } - intros d tr1 (Heq1&Heq2&Heq3). - destruct (Heq3 tgp) as (itp'&itp2&Hitp'&Hitp2&Heq). - 1: eapply Hlup. - assert (itp = itp') as <- by by eapply tree_lookup_unique. - specialize (Heq off) as (Hprot&Heq). - inversion Heq as [pp1 X1 HH|ini1 confl1 confl2 HprotX HP1 HP2 HeqX1 HeqX2|ini1 confl1 confl2 HnoProt HeqX1 HeqX2|p1 p2 HP1 HP2 HeqX1 HeqX2|wit_tg lp1 lp2 Hdip1 Hdip2 HiniX HeqX1 HeqX2|ini1 confl1 confl2 wit_tg HF1 HeqX1 HeqX2|p1 p2 ini Hd HeqX1 HeqX2]; simplify_eq. - - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - rewrite -HH -Hprot. - eapply tree_equal_transfer_is_disabled. 1-3: eassumption. 2: eapply tree_equal_sym; done. done. - - rewrite -HeqX1 in Hdisp. - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - inversion Hdisp as [|lp prot HH1 HH2 HH3]; simplify_eq. - rewrite -HeqX2 -Hprot. econstructor 2. - eapply tree_equal_transfer_pseudo_disabled in HH1. 2-4: done. 2: by eapply tree_equal_sym. - by eapply conflicted_transfer_pseudo_disabled. - - rewrite -HeqX1 in Hdisp. - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - inversion Hdisp as [|lp prot HH1 HH2 HH3]; simplify_eq. - rewrite -HeqX2 -Hprot. econstructor 2. - eapply tree_equal_transfer_pseudo_disabled in HH1. 2-4: done. 2: by eapply tree_equal_sym. - by eapply conflicted_transfer_pseudo_disabled. - - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - rewrite -HeqX2. econstructor 2. rewrite -Hprot. done. - - inversion Hdip2 as [itwF incl H1 H2 H3]. - inversion Hdip1 as [itwF' incl' H1' H2' H3']. - assert (incl = incl') as <-. - { rewrite Heq2 H1 in H1'. by simplify_eq. } - rewrite /rel_dec in H1'. destruct decide as [HPCF|] in H1'; last done. - clear H1'. destruct HPCF as [<-|Hne]. - 1: { assert (itwF = itp2) as <- by by eapply tree_lookup_unique. - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. done. } - exfalso. eapply Hothers. 2: exact Hne. 1: done. done. - - rewrite -HeqX1 in Hdisp. - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - inversion Hdisp as [|lp prot HH1 HH2 HH3]; simplify_eq. - rewrite -HeqX2 -Hprot. econstructor 2. - eapply tree_equal_transfer_pseudo_disabled in HH1. 2-4: done. 2: by eapply tree_equal_sym. - by eapply conflicted_transfer_pseudo_disabled. - - rewrite -HeqX1 in Hdisp. - econstructor. 2: exact Hitp2. - 1: rewrite -Heq2 /rel_dec decide_True //. - inversion Hdisp as [|lp prot HH1 HH2 HH3]; simplify_eq. - 1: destruct d; inversion Hd; done. - rewrite -HeqX2 -Hprot. econstructor 2. - eapply tree_equal_transfer_pseudo_disabled in HH1. 2-4: done. 2: by eapply tree_equal_sym. - eapply transfer_pseudo_disabled_notimm. 1: exact HH1. all: destruct d; inversion Hd; done. - Qed. - - Lemma trees_equal_transfer_disabled_in_practice_twice {d1 d2 tr1 tr2 tr3 tgpar tgcld off} : - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d1 tr1 tr2 → - tree_equal d2 tr2 tr3 → - disabled_in_practice tr2 tgcld tgpar off → - ∃ tgpar', - disabled_in_practice tr1 tgcld tgpar' off ∧ - disabled_in_practice tr2 tgcld tgpar' off ∧ - disabled_in_practice tr3 tgcld tgpar' off. - Proof. - intros H1 Hu1 Hu2 H2%tree_equal_sym H3 Hdip. - odestruct trees_equal_transfer_disabled_in_practice_many as (tg&Htg&Htg2). - 1: exact H1. 1-2: done. 1: exact Hdip. - exists tg. split_and!. - - by eapply Htg2. - - done. - - eapply Htg2. done. - Qed. - - Lemma trees_equal_transfer_frozen_in_practice_many {tr2 tgpar tgcld off} : - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr2 → - no_active_cousins C tr2 → - frozen_in_practice tr2 tgcld tgpar off → - (frozen_in_practice tr2 tgcld tgpar off ∧ - (∀ d tr', tree_equal d tr2 tr' → ∃ p, parent_has_perm p tr' tgcld tgpar off ∧ (p = Frozen ∨ p = Active ∧ d = Forwards))) ∨ - (∃ tgpar', disabled_in_practice tr2 tgcld tgpar' off ∧ - ∀ d tr', tree_equal d tr2 tr' → disabled_in_practice tr' tgcld tgpar' off). - Proof. - intros Hunq1 Hwf1 Hwf2 Hdip. - inversion Hdip as [itw incl Hrel Hlu Hperm Hinit]. - rewrite /rel_dec in Hrel. destruct decide as [HPCo|?]; try done. - destruct (trees_equal_decide_disabled_in_practice tr2 tgcld off) as [(tgp&itp&Hlup&Hdisp&HPC&Hothers)|HR]. - 1: done. - { eapply contains_child. 1: done. eapply Hlu. } - - odestruct trees_equal_transfer_disabled_in_practice_many as (tg&Htg). - 1: exact Hunq1. 1-2: done. 2: { right. exists tg. exact Htg. } - econstructor. 3: done. 2: done. rewrite /rel_dec decide_True //. - - left. split. - 1: done. - intros d tr1 (Heq1&Heq2&Heq3). - destruct (Heq3 tgpar) as (itw'&itw2&Hitw'&Hitw2&Heq). - 1: eapply Hlu. - assert (itw = itw') as <- by by eapply tree_lookup_unique. - assert (∃ p, item_lookup itw2 off = mkPerm PermInit p ∧ (p = Frozen ∨ p = Active ∧ d = Forwards)) as (p&Hitlu&Hp). - { specialize (Heq off) as (HeqL1&HeqL2). - inversion HeqL2 as [pp1|ini1 confl1 confl2 HprotX HP1 HP2 HeqX1 HeqX2|ini1 confl1 confl2 HnoProt HeqX1 HeqX2|lp1 lp2 Hdip1 Hdip2 HeqX1 HeqX2|wit_tg lp1 lp2 Hdip1 Hdip2 HiniX HeqX1 HeqX2|ini1 confl1 confl2 wit_tg HF1 HeqX1 HeqX2|p1 p2 ini Hd HeqX1 HeqX2]; simplify_eq. - + exists Frozen; split; last tauto. destruct item_lookup; simpl in *; simplify_eq. done. - + rewrite -HeqX1 // in Hperm. - + rewrite -HeqX1 // in Hperm. - + rewrite -HeqX1 // in Hinit. - + exists Frozen; split; last tauto. inversion Hdip1 as [itw1' incl1 Hrel1 Hlu1 Hperm1]. - rewrite /rel_dec in Hrel1. destruct decide as [HPC1|?] in Hrel1; last done. - eapply HR in Hperm1. 1: done. 1: done. - eapply ParentChild_transitive. 2: eassumption. done. - + rewrite -HeqX1 // in Hperm. - + rewrite -HeqX1 /= in Hperm Hinit; subst ini. - f_equal. destruct d; inversion Hd; simplify_eq. - eexists; split; first done. by right. } - exists p. split; last done. econstructor. 2: exact Hitw2. - 1: rewrite -Heq2 /rel_dec decide_True //. - all: by rewrite Hitlu. - Qed. - - Lemma item_apply_access_effect_on_initialized - {it it' l b kind rel range} - (Acc : item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C rel range it = Some it') - : initialized (item_lookup it' l) - = if decide (range'_contains range l) - then most_init (initialized (item_lookup it l)) (requires_init rel) - else initialized (item_lookup it l). - Proof. - unfold item_apply_access, permissions_apply_range' in Acc. - rewrite bind_Some in Acc; destruct Acc as [iperm' [iperm'Spec Inj]]. - injection Inj; clear Inj; intros; subst. - pose proof (mem_apply_range'_spec _ _ l _ _ iperm'Spec) as LocalSpec. - case_match. - 2: { rewrite /item_lookup /=. f_equal. f_equal. assumption. } - destruct LocalSpec as [val [valSpec MaybeApply]]. - unfold item_lookup; simpl. - rewrite valSpec; clear valSpec; simpl. - (* Now it's time to actually unfold [maybe_non_children_only] and [apply_access_perm] where - [initialized] *might* be modified. *) - unfold maybe_non_children_only in MaybeApply. rewrite most_init_comm. case_match. - - unfold nonchildren_only in MaybeApply. case_match. - + simpl. case_match. - * injection MaybeApply; intros; subst; reflexivity. - * unfold apply_access_perm in MaybeApply. - destruct (apply_access_perm_inner _ _ _ _); simpl in *; last congruence. - destruct (if most_init _ _ then _ else _); simpl in MaybeApply; last congruence. - injection MaybeApply; clear MaybeApply; intros; subst. - simpl. rewrite most_init_noop. reflexivity. - + unfold apply_access_perm in MaybeApply. - destruct (apply_access_perm_inner _ _ _ _); simpl in *; last congruence. - destruct (if most_init _ _ then _ else _); simpl in MaybeApply; last congruence. - injection MaybeApply; clear MaybeApply; intros; subst. - simpl. rewrite most_init_absorb. reflexivity. - - unfold apply_access_perm in MaybeApply. - destruct (apply_access_perm_inner _ _ _ _); simpl in *; last congruence. - destruct (if most_init _ _ then _ else _); simpl in MaybeApply; last congruence. - injection MaybeApply; clear MaybeApply; intros; subst. - simpl. rewrite most_init_comm. reflexivity. - Qed. - - Lemma perm_eq_up_to_C_preserved_by_access (b:bool) - {d tr1 tr1' tr2 tr2' it1 it1' it2 it2' tg l acc_tg kind range} (Hunq : wf_tree tr2) - (SameProt : iprot it1 = iprot it2) - (SameTg : itag it1 = itag it2) (* note: redundant *) - (SameRel : forall tg tg', rel_dec tr1 tg tg' = rel_dec tr2 tg tg') - (Unq1 : wf_tree tr1) - (Unq2 : wf_tree tr2) - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 → - perm_eq_up_to_C tr1 tr2 tg l (iprot it1) d (item_lookup it1 l) (item_lookup it2 l) -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1 = Some tr1' -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr2 = Some tr2' -> - tree_lookup tr1 tg it1 -> - tree_lookup tr1' tg it1' -> - tree_lookup tr2 tg it2 -> - tree_lookup tr2' tg it2' -> - tree_contains acc_tg tr2 -> - tree_contains acc_tg tr1 -> - item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr1 acc_tg (itag it1)) range it1 = Some it1' -> - item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr2 acc_tg (itag it2)) range it2 = Some it2' -> - perm_eq_up_to_C tr1' tr2' tg l (iprot it1') d (item_lookup it1' l) (item_lookup it2' l). - Proof. - intros Hpma1 Hnac1 Hpma2 Hnac2 HeqTree EqC Acc1 Acc2 Lookup1 Lookup1' Lookup2 Lookup2' Hacctg1 Hacctg2 ItAcc1 ItAcc2. - inversion EqC as [ - p pSpec Equal - |ini confl1 confl2 Prot Confl1 Confl2 itLookup1 itLookup2 - |ini confl1 confl2 NoProt itLookup1 itLookup2 - |p1 p2 Confl1 Confl2 itLookup1 itLookup2 - |????? SameInit - |ini confl1 confl2 witness_tg Hfrz itLookup1 itLookup2 - |p1 p2 ini H1 itLookup1 itLookup2 - ]. - - (* reflexive case *) - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [PermsAcc1 it1'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [PermsAcc2 it2'Spec]]. - injection it2'Spec; intros; subst; clear it2'Spec. - simpl. - pose proof (mem_apply_range'_spec _ _ l _ _ PermsAcc1) as Perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ PermsAcc2) as Perms2'Spec. - destruct (decide _). - + (* within range *) - destruct Perms1'Spec as [p1 [LookupSome1' PermAcc1]]. - destruct Perms2'Spec as [p2 [LookupSome2' PermAcc2]]. - rewrite /item_lookup LookupSome1' LookupSome2' /=. - rewrite /item_lookup in Equal. - rewrite Equal SameRel SameProt SameTg in PermAcc1. - rewrite PermAcc1 in PermAcc2. - injection PermAcc2; intros; subst. constructor. - + (* outside range *) - rewrite /item_lookup in Equal. - rewrite /item_lookup /= Perms1'Spec Perms2'Spec Equal. - constructor. - - (* The permissions are pseudo-conflicted, this restricts the possible accesses. *) - rewrite SameRel SameTg in ItAcc1. - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [perms1'Spec it1'Spec]]. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [perms2'Spec it2'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - injection it2'Spec; intros; subst; clear it2'Spec. - rewrite /item_lookup /=. - pose proof (mem_apply_range'_spec _ _ l _ _ perms1'Spec) as perm1'Spec; clear perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ perms2'Spec) as perm2'Spec; clear perms2'Spec. - (* Now we do the case analysis of the access that occured *) - (* First off, if we're out of range then we can take the exact same witness. *) - destruct (decide (range'_contains range l)). - 2: { - rewrite perm1'Spec. - rewrite perm2'Spec. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 -itLookup2. - econstructor. - + assumption. - + inversion Confl1; subst. - * constructor. - * eapply access_preserves_pseudo_conflicted_activable; eassumption. - + inversion Confl2; subst. - * constructor. - * eapply access_preserves_pseudo_conflicted_activable; eassumption. - } - (* Now we're within range *) - destruct perm1'Spec as [perm1' [perm1'Lookup perm1'Spec]]. - destruct perm2'Spec as [perm2' [perm2'Lookup perm2'Spec]]. - rewrite perm1'Lookup perm2'Lookup; clear perm1'Lookup perm2'Lookup. - simpl. - rewrite bool_decide_eq_true_2 in perm1'Spec; [|assumption]. - rewrite bool_decide_eq_true_2 in perm2'Spec; [|rewrite -SameProt; assumption]. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 in perm1'Spec; clear itLookup1. - rewrite -itLookup2 in perm2'Spec; clear itLookup2. - destruct (maybe_non_children_only_effect_or_nop b (apply_access_perm kind) (rel_dec tr2 acc_tg (itag it2))) as [Heff|Heff]. - all: rewrite !Heff /= in perm1'Spec,perm2'Spec. - 2: { simplify_eq. econstructor; first done. all: by eapply access_preserves_pseudo_conflicted. } - (* Next we need to unwrap the apply_access_perm to get to apply_access_perm_inner *) - rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [perm1 [perm1Spec perm1'Spec]]. - rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [tmp1 [tmp1Spec perm1'Spec]]. - injection perm1'Spec; simpl; intros; subst; clear perm1'Spec. - rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [perm2 [perm2Spec perm2'Spec]]. - rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [tmp2 [tmp2Spec perm2'Spec]]. - injection perm2'Spec; simpl; intros; subst; clear perm2'Spec. - simpl in *. - (* We can finally start the big case analysis at the level of the state machine *) - destruct (most_init _), perm1, perm2; try congruence. - all: injection tmp1Spec; intros; subst; clear tmp1Spec. - all: injection tmp2Spec; intros; subst; clear tmp2Spec. - all: destruct kind, (rel_dec _ _ _) eqn:relation, confl1; simpl in *; try discriminate. - all: destruct confl2; simpl in *; try discriminate. - all: try (injection perm1Spec; intros; subst); clear perm1Spec. - all: try (injection perm2Spec; intros; subst); clear perm2Spec. - all: try constructor; auto. - all: try constructor. - (* Now they are all ResActivable and we need to show that the cousin is still a witness. - See the above lemma for exactly that. *) - all: eapply access_preserves_pseudo_conflicted_activable; eassumption. - - (* The permissions are formerly pseudo-conflicted, but the difference should no longer matter now. *) - rewrite SameRel SameTg in ItAcc1. - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [perms1'Spec it1'Spec]]. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [perms2'Spec it2'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - injection it2'Spec; intros; subst; clear it2'Spec. - rewrite /item_lookup /=. - pose proof (mem_apply_range'_spec _ _ l _ _ perms1'Spec) as perm1'Spec; clear perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ perms2'Spec) as perm2'Spec; clear perms2'Spec. - (* Now we do the case analysis of the access that occured *) - (* First off, if we're out of range then we can take the exact same witness. *) - destruct (decide (range'_contains range l)). - 2: { - rewrite perm1'Spec. - rewrite perm2'Spec. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 -itLookup2. - econstructor 3. - assumption. - } - (* Now we're within range *) - destruct perm1'Spec as [perm1' [perm1'Lookup perm1'Spec]]. - destruct perm2'Spec as [perm2' [perm2'Lookup perm2'Spec]]. - rewrite perm1'Lookup perm2'Lookup; clear perm1'Lookup perm2'Lookup. - simpl. - rewrite bool_decide_eq_false_2 in perm1'Spec; [|assumption]. - rewrite bool_decide_eq_false_2 in perm2'Spec; [|rewrite -SameProt; assumption]. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 in perm1'Spec; clear itLookup1. - rewrite -itLookup2 in perm2'Spec; clear itLookup2. - destruct (maybe_non_children_only_effect_or_nop b (apply_access_perm kind) (rel_dec tr2 acc_tg (itag it2))) as [Heff|Heff]. - all: rewrite !Heff /= in perm1'Spec,perm2'Spec. - 2: { simplify_eq. econstructor; first done. all: by eapply access_preserves_pseudo_conflicted. } - (* Next we need to unwrap the apply_access_perm to get to apply_access_perm_inner *) - rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [perm1 [perm1Spec perm1'Spec]]. - rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [tmp1 [tmp1Spec perm1'Spec]]. - injection perm1'Spec; simpl; intros; subst; clear perm1'Spec. - rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [perm2 [perm2Spec perm2'Spec]]. - rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [tmp2 [tmp2Spec perm2'Spec]]. - injection perm2'Spec; simpl; intros; subst; clear perm2'Spec. - simpl in *. - (* We can finally start the big case analysis at the level of the state machine *) - edestruct (most_init ini _), perm1, perm2; try congruence. - all: injection tmp1Spec; intros; subst; clear tmp1Spec. - all: injection tmp2Spec; intros; subst; clear tmp2Spec. - all: destruct kind, (rel_dec _ _ _) eqn:relation, confl1; simpl in *; try discriminate. - all: destruct confl2; simpl in *; try discriminate. - all: try (injection perm1Spec; intros; subst); clear perm1Spec. - all: try (injection perm2Spec; intros; subst); clear perm2Spec. - all: try by econstructor 1. - all: try by econstructor 3. - (* pseudo-disabled *) - - rewrite SameRel SameTg in ItAcc1. - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [perms1'Spec it1'Spec]]. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [perms2'Spec it2'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - injection it2'Spec; intros; subst; clear it2'Spec. - rewrite /item_lookup /=. - pose proof (mem_apply_range'_spec _ _ l _ _ perms1'Spec) as perm1'Spec; clear perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ perms2'Spec) as perm2'Spec; clear perms2'Spec. - (* Now we do the case analysis of the access that occured *) - (* First off, if we're out of range then we can take the exact same witness. *) - destruct (decide (range'_contains range l)). - 2: { - rewrite perm1'Spec. - rewrite perm2'Spec. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 -itLookup2. - econstructor 4. - all: eapply access_preserves_pseudo_disabled; first done. - all: done. - } - (* Now we're within range *) - destruct perm1'Spec as [perm1' [perm1'Lookup perm1'Spec]]. - destruct perm2'Spec as [perm2' [perm2'Lookup perm2'Spec]]. - rewrite perm1'Lookup perm2'Lookup; clear perm1'Lookup perm2'Lookup. - simpl. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 in perm1'Spec; clear itLookup1. - rewrite -itLookup2 in perm2'Spec; clear itLookup2. - edestruct (maybe_non_children_only_effect_or_nop b (apply_access_perm kind) (rel_dec tr2 acc_tg (itag it2))) as [Heff|Heff]. - all: rewrite !Heff /= in perm1'Spec,perm2'Spec. all: clear Heff. - 2: { injection perm1'Spec as <-. injection perm2'Spec as <-. - econstructor 4. - all: eapply access_preserves_pseudo_disabled; first done. - all: done. } - (* Next we need to unwrap the apply_access_perm to get to apply_access_perm_inner *) - rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [perm1 [perm1Spec perm1'Spec]]. - rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [perm2 [perm2Spec perm2'Spec]]. - assert (¬ ParentChildIn (itag it2) acc_tg tr2) as HnPC. - { intros HnPC. clear perm1'Spec perm1Spec. - inversion Confl2 as [|tg_cs it_cs X1 X2 H1 H2 H3 H4 H5]; simplify_eq. - 1: { rewrite /apply_access_perm_inner /= in perm2Spec. - rewrite /rel_dec decide_True // in perm2Spec. by destruct kind. } - destruct (apply_access_spec_per_node (proj1 H2) (proj2 H2) Acc2) - as (cous' & cous'_spec & cous'_ex & cous'_det). - symmetry in cous'_spec. - rewrite bind_Some in cous'_spec. - destruct cous'_spec as (perms' & perms'_spec & cous'_build). - injection cous'_build; intros; subst; clear cous'_build. - pose proof (mem_apply_range'_spec _ _ l _ _ perms'_spec) as effect_at_l. - rewrite decide_True // in effect_at_l. - destruct effect_at_l as (perm' & perm'_lookup & perm'_spec). - rewrite /item_lookup in H4. rewrite H4 in perm'_spec. - rewrite bool_decide_true in perm'_spec. 2: done. - assert (tg_cs = itag it_cs) as -> by (symmetry; by eapply tree_lookup_correct_tag). - assert (tg = itag it2) as -> by (symmetry; by eapply tree_lookup_correct_tag). - rewrite /rel_dec decide_False in perm'_spec. - 2: { intros Hx. eapply cousins_have_disjoint_children. 4: eassumption. 4-5: done. - all: eapply Hunq. 1: done. 1: eapply Lookup2. 1: eapply H2. } - rewrite decide_False in perm'_spec. - 2: { intros Hx. rewrite /rel_dec in H1. - destruct decide as [|HH1] in H1; first done. - destruct decide as [|HH2] in H1; first done. - eapply HH2. eapply ParentChild_transitive. 2: exact Hx. 1: done. } - rewrite maybe_non_children_only_no_effect in perm'_spec. 2: done. - destruct kind in perm'_spec; cbv in perm'_spec; done. } - rewrite /rel_dec decide_False // /= in perm2'Spec. injection perm2'Spec as <-. - rewrite /rel_dec decide_False // /= in perm1'Spec. injection perm1'Spec as <-. - rewrite /rel_dec decide_False // /= in perm2Spec. - rewrite /rel_dec decide_False // /= in perm1Spec. - econstructor 4; eapply access_preserves_pseudo_disabled. 2,4: done. - + inversion Confl1 as [|X1 X2 X3 X4 X5 X6 X7 X8 H]; simplify_eq. - 1: destruct kind, bool_decide in perm1Spec; cbv in perm1Spec; injection perm1Spec as <-; econstructor 1. - econstructor 2. 1-4: done. - intros ->. - destruct (bool_decide (protector_is_active (iprot it1) C)), kind, p1 as [[]| | | |]; try discriminate perm1Spec. - all: done. - + inversion Confl2 as [|X1 X2 X3 X4 X5 X6 X7 X8 H]; simplify_eq. - 1: destruct kind, bool_decide in perm1Spec; cbv in perm2Spec; injection perm2Spec as <-; econstructor 1. - econstructor 2. 1-4: done. - intros ->. - destruct (bool_decide (protector_is_active (iprot it2) C)), kind, p2 as [[]| | | |]; try discriminate perm2Spec. - all: done. - - econstructor. - + eapply disabled_in_practice_tree_apply_access_irreversible; last eassumption. 2-3: done. - eassumption. - + eapply disabled_in_practice_tree_apply_access_irreversible; last eassumption. 2-3: done. - eassumption. - + rewrite (item_apply_access_effect_on_initialized ItAcc1). - rewrite (item_apply_access_effect_on_initialized ItAcc2). - rewrite SameInit. - case_match; last reflexivity. - f_equal. f_equal. rewrite SameTg. apply SameRel. - - (* Proof idea: - each item is Reserved. Therefore it can: - - get a child read: nothing happens - - get a child write: it's UB, since the parent is frozen - - get a foreign read: the conflictedness might change but that's OK, this case is precisely for that - - get a foreign write: it's either UB or we remain, depending on interior mutability. - + however, since such a write must disable our parent, it should not matter that IM is the same here. - But reasoning about this is complicated (because of maybe_nonchildren_only) so let's just not. *) - (* We're frozen in practice *) - pose trd := (match d with Forwards => tr1 | Backwards => tr2 end). fold trd in Hfrz. - pose trd' := (match d with Forwards => tr2 | Backwards => tr1 end). - eapply trees_equal_transfer_frozen_in_practice_many in Hfrz as [(Hfrz&Hfrzo)|(tdis&Htdis&Htdiso)]. - 3-5: by destruct d. - 2: { econstructor. - + eapply disabled_in_practice_tree_apply_access_irreversible; last eassumption. 2-3: done. - destruct d; try done. eapply Htdiso, tree_equal_sym, HeqTree. - + eapply disabled_in_practice_tree_apply_access_irreversible; last eassumption. 2-3: done. - destruct d; try done. eapply Htdiso, HeqTree. - + rewrite (item_apply_access_effect_on_initialized ItAcc1). - rewrite (item_apply_access_effect_on_initialized ItAcc2). - rewrite -itLookup1 -itLookup2 /=. - case_match; last reflexivity. - f_equal. f_equal. rewrite SameTg. apply SameRel. } - destruct (Hfrzo Forwards trd') as (p'&Hfrzalmost&Hfrz'). - 1: destruct d; first done. 1: eapply tree_equal_sym in HeqTree; exact HeqTree. - rewrite SameRel SameTg in ItAcc1. - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [perms1'Spec it1'Spec]]. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [perms2'Spec it2'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - injection it2'Spec; intros; subst; clear it2'Spec. - rewrite /item_lookup /=. - pose proof (mem_apply_range'_spec _ _ l _ _ perms1'Spec) as perm1'Spec; clear perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ perms2'Spec) as perm2'Spec; clear perms2'Spec. - (* Now we do the case analysis of the access that occured *) - (* First off, if we're out of range then we can take the exact same witness. *) - destruct (decide (range'_contains range l)) eqn:Hrangedec. - 2: { - rewrite perm1'Spec. - rewrite perm2'Spec. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 -itLookup2. - econstructor 6; destruct d. - - eapply frozen_in_practice_tree_apply_access_irreversible in Hfrz. 4: exact Acc1. 2-3: done. - destruct Hfrz as [(Hf&HX)|(Hf&HX)]; first done. - rewrite /becomes_disabled Hrangedec in HX. done. - - eapply frozen_in_practice_tree_apply_access_irreversible in Hfrz. 4: exact Acc2. 2-3: done. - destruct Hfrz as [(Hf&HX)|(Hf&HX)]; first done. - rewrite /becomes_disabled Hrangedec in HX. done. - } - (* Now we're within range *) - destruct perm1'Spec as [perm1' [perm1'Lookup perm1'Spec]]. - destruct perm2'Spec as [perm2' [perm2'Lookup perm2'Spec]]. - rewrite perm1'Lookup perm2'Lookup; clear perm1'Lookup perm2'Lookup. - simpl. - rewrite /item_lookup in itLookup1, itLookup2. - rewrite -itLookup1 in perm1'Spec; clear itLookup1. - rewrite -itLookup2 in perm2'Spec; clear itLookup2. - assert (∃ p, parent_has_perm p (match d with Backwards => tr1 | _ => tr2 end) tg witness_tg l ∧ (p = Frozen ∨ p = Active)) as (pt&Htrans&Hptrans). - { destruct Hfrz' as [ -> |(->&_)]; eexists; (split; first done). all: tauto. } - eapply @frozen_in_practice_tree_apply_access_irreversible with (tr' := match d with Forwards => _ | _ => _ end) in Hfrz; last (destruct d; [exact Acc1|exact Acc2]). 2-3: by destruct d. - destruct Hfrz as [(H1&HX)|(H1&HX)]. - all: edestruct (maybe_non_children_only_effect_or_nop b (apply_access_perm kind) (rel_dec tr2 acc_tg (itag it2))) as [Heff|Heff]. - all: rewrite !Heff /= in perm1'Spec,perm2'Spec; clear Heff. - 2: { simplify_eq. econstructor 6; eassumption. } - 3: { eapply @parent_has_perm_similarly_disabled with (tr' := match d with Forwards => tr2' | _ => tr1' end) in Htrans. - 4: by destruct d. 4: by destruct d. 3: destruct d; done. - 3: { rewrite /becomes_disabled in HX|-*. destruct d. - 1: rewrite -SameRel //. rewrite SameRel //. } - 2: destruct Hptrans; by simplify_eq. - econstructor 5. 3: by simplify_eq. - all: eapply parent_has_disabled_perm_is_pseudo_disabled; by destruct d. } - (* Next we need to unwrap the apply_access_perm to get to apply_access_perm_inner *) - all: rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [perm1 [perm1Spec perm1'Spec]]. - all: rewrite bind_Some in perm1'Spec; destruct perm1'Spec as [tmp1 [tmp1Spec perm1'Spec]]. - all: injection perm1'Spec; simpl; intros; subst; clear perm1'Spec. - all: rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [perm2 [perm2Spec perm2'Spec]]. - all: rewrite bind_Some in perm2'Spec; destruct perm2'Spec as [tmp2 [tmp2Spec perm2'Spec]]. - all: injection perm2'Spec; simpl; intros; subst; clear perm2'Spec. - 2: { eapply @parent_has_perm_similarly_disabled with (tr' := match d with Forwards => tr2' | _ => tr1' end) in Htrans. - 4: by destruct d. 4: by destruct d. 3: destruct d; done. - 3: { rewrite /becomes_disabled in HX|-*. destruct d. - 1: rewrite -SameRel //. rewrite SameRel //. } - 2: destruct Hptrans; by simplify_eq. - econstructor 5. 3: by simplify_eq. - all: eapply parent_has_disabled_perm_is_pseudo_disabled; by destruct d. } - simpl in *. rewrite -SameProt in tmp2Spec,perm2Spec. - (* We can finally start the big case analysis at the level of the state machine *) - edestruct (most_init ini _), perm1, perm2, (bool_decide (protector_is_active (iprot it1) C)); try congruence. - all: injection tmp1Spec; intros; subst; clear tmp1Spec. - all: injection tmp2Spec; intros; subst; clear tmp2Spec. - all: destruct kind, (rel_dec _ _ _) eqn:relation, confl1; simpl in *; try discriminate. - all: destruct confl2; simpl in *; try discriminate. - all: try (injection perm1Spec; intros; subst); clear perm1Spec. - all: try (injection perm2Spec; intros; subst); clear perm2Spec. - all: try by econstructor 1. - all: try by econstructor 6. - - (* asymmetric *) - rewrite bind_Some in ItAcc1; destruct ItAcc1 as [perms1' [PermsAcc1 it1'Spec]]. - injection it1'Spec; intros; subst; clear it1'Spec. - rewrite bind_Some in ItAcc2; destruct ItAcc2 as [perms2' [PermsAcc2 it2'Spec]]. - injection it2'Spec; intros; subst; clear it2'Spec. - simpl. - pose proof (mem_apply_range'_spec _ _ l _ _ PermsAcc1) as Perms1'Spec. - pose proof (mem_apply_range'_spec _ _ l _ _ PermsAcc2) as Perms2'Spec. - rewrite /item_lookup /= in itLookup1,itLookup2. - destruct (decide _); last first. - { rewrite /item_lookup /= Perms1'Spec Perms2'Spec -itLookup1 -itLookup2. - econstructor 7. done. } - destruct Perms1'Spec as [p1' [LookupSome1' PermAcc1]]. - destruct Perms2'Spec as [p2' [LookupSome2' PermAcc2]]. - rewrite -itLookup1 in PermAcc1. - rewrite -itLookup2 in PermAcc2. - rewrite -SameProt -SameTg -SameRel in PermAcc2. - edestruct maybe_non_children_only_effect_or_nop as [Heq|Heq]; erewrite Heq in PermAcc1, PermAcc2; clear Heq. - 2: { injection PermAcc1 as <-; injection PermAcc2 as <-. - rewrite /item_lookup /= LookupSome1' LookupSome2' /=. by econstructor 7. } - destruct ini, d, kind, (rel_dec tr1 acc_tg (itag it1)); simpl in *. - all: inversion H1 as [P|P]; subst P p1 p2; [ - rewrite bool_decide_eq_false_2 // in PermAcc1,PermAcc2 - | rewrite bool_decide_eq_true_2 // in PermAcc1,PermAcc2]. - all: rewrite /apply_access_perm /apply_access_perm_inner /= in PermAcc1,PermAcc2; - try discriminate PermAcc1; try discriminate PermAcc2; - injection PermAcc1 as <-; injection PermAcc2 as <-. - all: rewrite /item_lookup /= LookupSome1' LookupSome2' /=. - all: try econstructor 1. - all: econstructor 7; simpl; econstructor; done. - Qed. - - Lemma item_eq_up_to_C_preserved_by_access (b : bool) - {d tr1 tr1' tr2 tr2' it1 it1' it2 it2' tg acc_tg kind range} (Hunq1 : wf_tree tr1) (Hunq2 : wf_tree tr2) - (SameTg : itag it1 = itag it2) - (SameRel : forall tg tg', rel_dec tr1 tg tg' = rel_dec tr2 tg tg') - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 → - item_eq_up_to_C tr1 tr2 tg d it1 it2 -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1 = Some tr1' -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr2 = Some tr2' -> - tree_lookup tr1 tg it1 -> - tree_lookup tr1' tg it1' -> - tree_lookup tr2 tg it2 -> - tree_lookup tr2' tg it2' -> - tree_contains acc_tg tr1 -> - tree_contains acc_tg tr2 -> - item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr1 acc_tg (itag it1)) range it1 = Some it1' -> - item_apply_access (maybe_non_children_only b (apply_access_perm kind)) C (rel_dec tr2 acc_tg (itag it2)) range it2 = Some it2' -> - item_eq_up_to_C tr1' tr2' tg d it1' it2'. - Proof. - intros ????? EqC Acc1 Acc2 Lookup1 Lookup1' Lookup2 Lookup2' AccTg1 AccTg2 ItAcc1 ItAcc2. - econstructor. - - rewrite <- (proj1 (proj2 (item_apply_access_preserves_metadata _ _ ItAcc1))). - rewrite <- (proj1 (proj2 (item_apply_access_preserves_metadata _ _ ItAcc2))). - apply EqC. assumption. - - eapply perm_eq_up_to_C_preserved_by_access. - + done. - + apply EqC. assumption. - + apply SameTg. - + apply SameRel. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + apply EqC. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - + eassumption. - Qed. - - Lemma tree_equal_preserved_by_access_maybe_nonchildren_only (b : bool) - {d tr1 tr2 tr1' tr2' kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 -> - tree_contains acc_tg tr1 -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr1 = Some tr1' -> - tree_apply_access (maybe_non_children_only b (apply_access_perm kind)) C acc_tg range tr2 = Some tr2' -> - tree_equal d tr1' tr2'. - Proof. - intros ???? Heq. pose proof Heq as [SameTg [SameRel EqC]]. intros ExAcc Acc1 Acc2. - split; [|split]. - - intros tg. - rewrite <- (access_preserves_tags Acc1). - rewrite <- (access_preserves_tags Acc2). - apply SameTg. - - intros tg tg'. - rewrite <- (access_same_rel_dec Acc1). - rewrite <- (access_same_rel_dec Acc2). - apply SameRel. - - intros tg Ex1'. - pose proof (proj2 (access_preserves_tags Acc1) Ex1') as Ex1. - pose proof (proj1 (SameTg _) Ex1) as Ex2. - pose proof (proj1 (access_preserves_tags Acc2) Ex2) as Ex2'. - destruct (EqC tg Ex1) as [it1 [it2 [Lookup1 [Lookup2 EqC12]]]]. - destruct (apply_access_spec_per_node Ex1 (proj2 Lookup1) Acc1) as [it1' [it1'Spec [_ Lookup1']]]. - destruct (apply_access_spec_per_node Ex2 (proj2 Lookup2) Acc2) as [it2' [it2'Spec [_ Lookup2']]]. - exists it1'. exists it2'. - split; [|split]. - + split; assumption. - + split; assumption. - + eapply item_eq_up_to_C_preserved_by_access. - * exact GloballyUnique1. - * exact GloballyUnique2. - * erewrite tree_lookup_correct_tag; [|exact Lookup1]. - erewrite tree_lookup_correct_tag; [|exact Lookup2]. - reflexivity. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * eassumption. - * split; eassumption. - * eassumption. - * split; eassumption. - * eassumption. - * by eapply SameTg. - * symmetry; assumption. - * symmetry; assumption. - Qed. - - Lemma tree_equal_preserved_by_memory_access - {d tr1 tr2 tr1' tr2' kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 -> - tree_contains acc_tg tr1 -> - memory_access kind C acc_tg range tr1 = Some tr1' -> - memory_access kind C acc_tg range tr2 = Some tr2' -> - tree_equal d tr1' tr2'. - Proof. - by eapply (tree_equal_preserved_by_access_maybe_nonchildren_only false). - Qed. - - Lemma tree_equal_preserved_by_memory_access_nonchildren_only - {d tr1 tr2 tr1' tr2' kind acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 -> - tree_contains acc_tg tr1 -> - memory_access_nonchildren_only kind C acc_tg range tr1 = Some tr1' -> - memory_access_nonchildren_only kind C acc_tg range tr2 = Some tr2' -> - tree_equal d tr1' tr2'. - Proof. - by eapply (tree_equal_preserved_by_access_maybe_nonchildren_only true). - Qed. - - Lemma tree_equal_memory_deallocate - {d tr1 tr2 tr1' tr2' acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal d tr1 tr2 -> - tree_contains acc_tg tr1 -> - memory_deallocate C acc_tg range tr1 = Some tr1' -> - memory_deallocate C acc_tg range tr2 = Some tr2' -> - tree_equal d tr1' tr2'. - Proof. - intros ???? Heq Hcontains (pw1&Hacc1&<-%join_map_id_is_Some_identical)%bind_Some - (pw2&Hacc2&<-%join_map_id_is_Some_identical)%bind_Some. - by eapply (@tree_equal_preserved_by_memory_access d tr1 tr2). - Qed. - - Lemma is_Some_if {A} (P : bool) (s:A) : is_Some (if P then Some s else None) → P. - Proof. - destruct P; first done. - intros (x&[=]). - Qed. - - Lemma is_Some_if_neg {A} (P : bool) (s:A) : is_Some (if P then None else Some s) → P = false. - Proof. - destruct P; last done. - intros (x&[=]). - Qed. - - Lemma tree_equal_allows_more_deallocation - {tr1 tr2 acc_tg range} - (GloballyUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (GloballyUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (ProtParentsNonDis : protected_parents_not_disabled C tr2) - (PMI : parents_more_init tr2) : - parents_more_active tr1 → - no_active_cousins C tr1 → - parents_more_active tr2 → - no_active_cousins C tr2 → - tree_equal Forwards tr1 tr2 -> - tree_unique acc_tg tr1 -> - is_Some (memory_deallocate C acc_tg range tr1) -> - is_Some (memory_deallocate C acc_tg range tr2). - Proof. - intros ???? Heq Hunq (tr1'&(pw1&Hpw1&Htrr%mk_is_Some)%bind_Some). - pose proof Hpw1 as HH. - eapply mk_is_Some, tree_equal_allows_more_access in HH as (pw2&Hpw2). 2-8: done. - opose proof (tree_equal_preserved_by_memory_access _ _ _ _ _ _ _ _ Hpw1 Hpw2) as Heqpw. - 1-3: done. 1-4: done. 1: by eapply unique_exists. - rewrite /memory_deallocate Hpw2 /option_bind //. - eapply join_success_condition, every_node_map, every_node_eqv_universal. - intros itm2 Hitm2%exists_node_to_tree_lookup. - 2: { intros ttg Hcont. - eapply access_preserves_tags, GloballyUnique2 in Hcont. - 2: apply Hpw2. setoid_rewrite <- tree_apply_access_preserve_unique; last apply Hpw2. - done. } - assert (tree_contains (itag itm2) pw2) as Hcont by apply Hitm2. - destruct Heqpw as (Hsame&_&Hacc). setoid_rewrite <- Hsame in Hcont. - apply Hacc in Hcont as (itm1&itm2'&Hlu1&Hlu2&Hiteq). - assert (itm2' = itm2) as ->. - 1: eapply tree_determined_unify. 1,3: eapply Hitm2. 1: eapply Hlu2. - assert (itag itm1 = itag itm2) as Htageq. - 1: eapply tree_lookup_correct_tag, Hlu1. - eapply join_success_condition in Htrr. - setoid_rewrite every_node_map in Htrr. - eapply every_node_eqv_universal in Htrr. - 2: { eapply tree_lookup_to_exists_node. rewrite -Htageq in Hlu1. done. } - simpl in Htrr. eapply is_Some_if_neg in Htrr. - destruct (Hiteq 0) as (Hloceq&_). simpl. - rewrite -!Hloceq Htrr. done. - Qed. - - Lemma trees_equal_insert d tr1 tr2 ttr1 ttr2 blk : - trees_equal d tr1 tr2 → - tree_equal d ttr1 ttr2 → - trees_equal d (<[blk := ttr1]> tr1) (<[blk := ttr2]> tr2). - Proof. - intros Htr Httr blk'. - destruct (decide (blk = blk')) as [Heq|Hne]. - - rewrite -!Heq !lookup_insert. by econstructor. - - rewrite !lookup_insert_ne //. - Qed. - - Lemma apply_within_trees_equal d fn blk tr1 tr1' tr2 : - (∀ ttr1 ttr1' ttr2, fn ttr1 = Some ttr1' → tree_equal d ttr1 ttr2 → - tr1 !! blk = Some ttr1 → tr1' !! blk = Some ttr1' → tr2 !! blk = Some ttr2 → - ∃ ttr2', fn ttr2 = Some ttr2' ∧ tree_equal d ttr1' ttr2') → - apply_within_trees fn blk tr1 = Some tr1' → - trees_equal d tr1 tr2 → - ∃ tr2', apply_within_trees fn blk tr2 = Some tr2' ∧ - trees_equal d tr1' tr2'. - Proof. - intros Hfn Happly Heq. - rewrite /apply_within_trees in Happly|-*. - specialize (Heq blk) as Heqblk. - inversion Heqblk as [ttr1 ttr2 Hteq Htr1 Htr2|HN1 HN2]; last rewrite -HN1 // in Happly. - rewrite -Htr1 -?Htr2 /= in Happly|-*. - destruct (fn ttr1) as [ttr1'|] eqn:Hfnttr1; last done. - rewrite /= in Happly. injection Happly as <-. - destruct (Hfn ttr1 ttr1' ttr2) as (ttr2' & Hfnttr2 & Heq'); try done. - 1: by rewrite lookup_insert. - rewrite Hfnttr2 /=. eexists; split; first done. - by apply trees_equal_insert. - Qed. - - Lemma trees_equal_delete d tr1 tr2 blk : - trees_equal d tr1 tr2 → - trees_equal d (delete blk tr1) (delete blk tr2). - Proof. - intros Htr blk'. - destruct (decide (blk = blk')) as [Heq|Hne]. - - rewrite -!Heq !lookup_delete. by econstructor. - - rewrite !lookup_delete_ne //. - Qed. - - Lemma trees_equal_init_trees d ts tt tg bl off sz : - trees_equal d ts tt → - trees_equal d (extend_trees tg bl off sz ts) (extend_trees tg bl off sz tt). - Proof. - intros Htrs. apply trees_equal_insert; first done. - eapply tree_equal_reflexive. - eapply wf_tree_tree_item_determined. - eapply wf_init_tree. - Qed. - - Lemma tree_all_protected_initialized_elem_of cid tr tg lst - (AllUnique : forall tg, tree_contains tg tr -> tree_unique tg tr) : - (tg, lst) ∈ tree_get_all_protected_tags_initialized_locs cid tr ↔ - ∃ it, tree_lookup tr tg it ∧ protector_is_for_call cid it.(iprot) ∧ - ∀ z v, lst !! z = Some v ↔ initialized (item_lookup it z) = PermInit ∧ (v = AccessWrite ↔ perm (item_lookup it z) = Active). - Proof. - setoid_rewrite tree_all_protected_initialized_exists_node. - split. - - intros (it&Hexit%exists_node_to_tree_lookup&Htg&Hprot&Hinit)%exists_node_eqv_existential. 2: done. - rewrite Htg in Hexit. by eexists. - - intros (it&Hit&Hprops). assert (itag it = tg) as <- by by eapply tree_lookup_correct_tag. - eapply exists_node_eqv_existential. eexists; split; last done. - by eapply tree_lookup_to_exists_node. - Qed. - - Lemma parents_not_disabled_child_not_prot_init tr tg1 tg2 it1 it2 off - (Hwf : wf_tree tr) - (HH : protected_parents_not_disabled C tr) : - tree_lookup tr tg1 it1 → - tree_lookup tr tg2 it2 → - ParentChildIn tg1 tg2 tr → - perm (item_lookup it1 off) = Disabled → - initialized (item_lookup it2 off) = PermInit → - protector_is_active (iprot it2) C → - False. - Proof. - intros Hl1 Hl2 HPC Hp1 Hp2 Hp3. - specialize (HH tg1). eapply every_child_ParentChildIn in HH. - 2: done. 2, 4: eapply Hwf. 2,4: eapply Hl1. 2: eapply Hl2. 2: done. - assert (tg1 = itag it1) as -> by by eapply tree_lookup_correct_tag in Hl1. - assert (tg2 = itag it2) as -> by by eapply tree_lookup_correct_tag in Hl2. - eapply every_node_eqv_universal in HH. - 2: eapply tree_lookup_to_exists_node, Hl2. - ospecialize (HH _ _ Hp2 Hp3). 1: done. congruence. - Qed. - - Lemma disabled_in_practice_not_prot_init tr tg1 tg2 it off - (Hwf : wf_tree tr) - (HNC : no_active_cousins C tr) - (HH : protected_parents_not_disabled C tr) : - tree_lookup tr tg2 it → - initialized (item_lookup it off) = PermInit → - protector_is_active (iprot it) C → - disabled_in_practice tr tg2 tg1 off → - False. - Proof. - intros Hl1 Hini Hperm [it_witness incl H1 H2 H3]. - destruct (decide (perm (item_lookup it_witness off) = Disabled)) as [Hdis|Hnondis]. - + eapply parents_not_disabled_child_not_prot_init. 1: exact Hwf. 1: done. 4: exact Hdis. 4: exact Hini. 4: exact Hperm. - 1-2: done. - rewrite /rel_dec in H1. destruct decide; done. - + inversion H3 as [X1 X2 X3|lp X HH1 HH2 X2]; simplify_eq. - { rewrite -X2 in Hnondis. done. } - inversion HH1 as [|tgcs itcs X1 X2 H1' H2' H3' H4 H5 X3 X4]; simplify_eq. - { rewrite -HH2 in Hnondis. done. } - eapply HNC. 1: exact Hl1. 1: exact H2'. 3: by erewrite H4. - 2: right; split. 2: done. 2: done. - rewrite rel_dec_flip2 /=. - rewrite /rel_dec in H1|-*. - destruct decide as [HPC1|] in H1; last done. clear H1. - rewrite decide_False; last first. - { intros HPC2. rewrite /rel_dec in H1'. - destruct decide in H1'; try done. - rewrite decide_True // in H1'. - eapply ParentChild_transitive. 1: exact HPC1. done. } - rewrite decide_False //. - intros HPC2. - eapply cousins_have_disjoint_children. 4: exact H1'. 4: exact HPC1. 4: done. - all: eapply Hwf. 1: eapply Hl1. 1: eapply H2. 1: eapply H2'. - Qed. - - Lemma item_wf_item_lookup_active it ev1 ev2 off : - item_wf it ev1 ev2 → - perm (item_lookup it off) = Active → - initialized (item_lookup it off) = PermInit. - Proof. - intros Hwf. - rewrite /item_lookup. destruct (iperm it !! off) as [p|] eqn:Heq. - - rewrite /=. eapply map_Forall_lookup_1 in Heq. 2: by eapply item_perms_valid. apply Heq. - - simpl. intros HH. exfalso; by eapply item_default_perm_valid. - Qed. - - - Lemma perm_eq_up_to_C_same_protected_active d tr1 tr2 tg off prot it1 it2 ev1 ev2 - (Hwf1 : wf_tree tr1) - (Hwf2 : wf_tree tr2) - (ProtParentsNonDis1 : protected_parents_not_disabled C tr1) - (ProtParentsNonDis2 : protected_parents_not_disabled C tr2) - (HCS1 : no_active_cousins C tr1) - (HCS2 : no_active_cousins C tr2) - (Hiwf1 : item_wf it1 ev1 ev2) - (Hiwf2 : item_wf it2 ev1 ev2) : - tree_lookup tr1 tg it1 → - tree_lookup tr2 tg it2 → - prot = iprot it1 → prot = iprot it2 → - protector_is_active prot C → - perm_eq_up_to_C tr1 tr2 tg off prot d (item_lookup it1 off) (item_lookup it2 off) → - perm (item_lookup it1 off) = Active ↔ perm (item_lookup it2 off) = Active. - Proof. - intros Hl1 Hl2 Hiprot1 Hiprot2 Hprot H. inversion H as [| | |p1 p2 HX1 HX2 HX3 HX4|X1 X2 X3 X4 X5 X6 X7| |p1 p2 ini Hr]; try done; simplify_eq. - - simpl; split; intros Hact; exfalso. - + rewrite /item_lookup in HX3. - destruct lookup eqn:Heq in HX3. - 2: { simpl in HX3. injection HX3 as ->. - eapply item_default_perm_valid in Hact; done. } - rewrite /= in HX3. subst. - eapply item_perms_valid in Heq. 2: done. - simpl in Heq. by ospecialize (Heq _). - + rewrite /item_lookup in HX4. - destruct lookup eqn:Heq in HX4. - 2: { simpl in HX3. injection HX4 as ->. - eapply item_default_perm_valid in Hact; done. } - rewrite /= in HX4. subst. - eapply item_perms_valid in Heq. 2: done. - simpl in Heq. by ospecialize (Heq _). - - split; intros XX; eapply item_wf_item_lookup_active in XX; try done. - all: exfalso; destruct d; - (eapply disabled_in_practice_not_prot_init in X4; [done..| |by congruence]). - all: congruence. - - destruct d; simpl in Hr; inversion Hr; simplify_eq; simpl. - 2,4: done. all: exfalso; done. - Qed. - - Lemma tree_equals_protected_initialized d tr1 tr2 cid ev1 ev2 - (AllUnique1 : forall tg, tree_contains tg tr1 -> tree_unique tg tr1) - (AllUnique2 : forall tg, tree_contains tg tr2 -> tree_unique tg tr2) - (PND1 : protected_parents_not_disabled C tr1) - (PND2 : protected_parents_not_disabled C tr2) - (HCS1 : no_active_cousins C tr1) - (HCS2 : no_active_cousins C tr2) - (Hiwf1 : tree_items_compat_nexts tr1 ev1 ev2) - (Hiwf2 : tree_items_compat_nexts tr2 ev1 ev2) : - cid ∈ C → - tree_equal d tr1 tr2 → - tree_get_all_protected_tags_initialized_locs cid tr1 = - tree_get_all_protected_tags_initialized_locs cid tr2. - Proof. - intros Hcid Heq. eapply gset_leibniz. intros (tg&lst). - split; intros (it&Hlu&Hprot&Hinit)%tree_all_protected_initialized_elem_of; try done. - all: eapply tree_all_protected_initialized_elem_of; first done. - - edestruct (tree_equal_transfer_lookup_1 Heq Hlu) as (it'&Hit'&Heqit'). - exists it'. split; first done. - split; first by erewrite <- item_eq_up_to_C_same_iprot. - intros z. specialize (Hinit z). destruct (Heqit' z) as (Hproteq&Heqlu). - erewrite <- perm_eq_up_to_C_same_init. 2: done. - setoid_rewrite <- perm_eq_up_to_C_same_protected_active. 15: eassumption. 2-7: try done. - 1,4,5,6,7: done. - + eapply every_node_eqv_universal in Hiwf1. 2: eapply tree_lookup_to_exists_node, Hlu. - exact Hiwf1. - + eapply every_node_eqv_universal in Hiwf2. 2: eapply tree_lookup_to_exists_node, Hit'. - exact Hiwf2. - + by eexists cid. - - edestruct (tree_equal_transfer_lookup_2 Heq Hlu) as (it'&Hit'&Heqit'). - exists it'. split; first done. - split; first by erewrite item_eq_up_to_C_same_iprot. - intros z. specialize (Hinit z). destruct (Heqit' z) as (Hproteq&Heqlu). - erewrite perm_eq_up_to_C_same_init. 2: done. - setoid_rewrite perm_eq_up_to_C_same_protected_active. 15: eassumption. 2-7: done. - 1,4,5,6,7: done. - + eapply every_node_eqv_universal in Hiwf1. 2: eapply tree_lookup_to_exists_node, Hit'. - exact Hiwf1. - + eapply every_node_eqv_universal in Hiwf2. 2: eapply tree_lookup_to_exists_node, Hlu. - exact Hiwf2. - + rewrite Hproteq. by eexists cid. - Qed. - - - Lemma tree_equals_access_many_helper_2 tg (L : gmap Z _) tr1 tr1' tr2 - (Hwf1 : wf_tree tr1) - (Hwf2 : wf_tree tr2) - (PMI : parents_more_init tr2) - (ProtParentsNonDis2 : protected_parents_not_disabled C tr2) : - parents_more_active tr1 → parents_more_active tr2 → - no_active_cousins C tr1 → no_active_cousins C tr2 → - tree_equal Forwards tr1 tr2 → - tree_unique tg tr1 → - let fn := (λ tr, map_fold (λ l acc tr2, tr2 ≫= memory_access_nonchildren_only acc C tg (l, 1%nat)) (Some tr) L) in - fn tr1 = Some tr1' → - ∃ tr2', fn tr2 = Some tr2' ∧ tree_equal Forwards tr1' tr2'. - Proof. - intros X1 X2 X3 X4 Heq Hunq''. simpl. - map_fold_weak_ind L as off acc E Hnone Hfoo IH in tr1' Hunq''. - { simpl. intros [= ->]; by eexists. } - simpl. intros (tr1'''&H1&H2)%bind_Some. - specialize (IH _ Hunq'' H1) as (tr2'''&Htr2&HHtr2p). rewrite Hfoo Htr2 /=. - assert (tree_unique tg tr1''') as Hunq'''. - { rewrite /tree_unique. erewrite <- tree_access_many_helper_2. 1: exact Hunq''. exact H1. } - assert (wf_tree tr1''') as Hwf1'''. - { eapply preserve_tag_count_wf. 1: eapply tree_access_many_helper_2. 1: exact Hwf1. 1: apply H1. } - assert (wf_tree tr2''') as Hwf2'''. - { eapply preserve_tag_count_wf. 1: eapply tree_access_many_helper_2. 1: exact Hwf2. 1: apply Htr2. } - opose proof (tree_equal_allows_more_access_nonchildren_only _ _ _ _ _ HHtr2p Hunq''' _) as (trr&Htrr). - 1, 2: by apply wf_tree_tree_unique. 3: done. - 1: { eapply tree_access_many_protected_not_disabled_helper_2. 5: exact Htr2. 1,3,4: done. destruct Heq as (Hx&_). by eapply Hx, unique_exists. } - 1: { eapply tree_access_many_more_init_helper_2. 4: exact Htr2. 1,3: done. destruct Heq as (Hx&_). by eapply Hx, unique_exists. } - 1: by eapply mk_is_Some. - exists trr; split; first done. - eapply tree_equal_preserved_by_memory_access_nonchildren_only. - 9-10: done. 7: done. 7: by eapply unique_exists. - 1-2: by eapply wf_tree_tree_unique. - 1,3: eapply tree_access_many_more_active_helper_2; last done; first done; last done. - 2: eapply Heq. 1-2: by eapply unique_exists. - all: eapply tree_access_many_no_cousins_helper_2; last done; first done; last done. - 2: eapply Heq. 1-2: by eapply unique_exists. - Qed. - - Lemma tree_equals_access_many_helper_1 (E : list (tag * gmap Z _)) tr1 tr1' tr2 - (Hwf1 : wf_tree tr1) - (Hwf2 : wf_tree tr2) - (PMI2 : parents_more_init tr2) - (ProtParentsNonDis : protected_parents_not_disabled C tr2) : - parents_more_active tr1 → parents_more_active tr2 → - no_active_cousins C tr1 → no_active_cousins C tr2 → - tree_equal Forwards tr1 tr2 → - (∀ tg L, (tg, L) ∈ E → tree_unique tg tr1)→ - let fn := (λ tr, foldr (λ '(tg, L) tr, tr ≫= λ tr1, map_fold (λ l acc tr2, tr2 ≫= memory_access_nonchildren_only acc C tg (l, 1%nat)) (Some tr1) L) (Some tr) E) in - fn tr1 = Some tr1' → - ∃ tr2', fn tr2 = Some tr2' ∧ tree_equal Forwards tr1' tr2'. - Proof. - intros X1 X2 X3 X4 Heq Hunq. - induction E as [|(tg&init_locs) S IH] in tr1',Hunq|-*. - { simpl. intros [= ->]; by eexists. } - simpl. intros (tr1''&H1&H2)%bind_Some. - opose proof (IH _ _ H1) as (tr2''&Htr2&HHtr2); clear IH. - { intros ???. eapply Hunq. by right. } - rewrite Htr2 /=. pose proof Hunq as Hunq2. - ospecialize (Hunq tg init_locs _). 1: by left. revert H2. - eapply tree_equals_access_many_helper_2. - { eapply preserve_tag_count_wf. 1: eapply tree_access_many_helper_1. 1: exact Hwf1. 1: apply H1. } - { eapply preserve_tag_count_wf. 1: eapply tree_access_many_helper_1. 1: exact Hwf2. 1: exact Htr2. } - { eapply tree_access_many_more_init_helper_1. 4: exact Htr2. 1,3: done. intros ???. destruct Heq as (HH&_); eapply HH, unique_exists, Hunq2. by right. } - { eapply tree_access_many_protected_not_disabled_helper_1. 5: exact Htr2. 1,3,4: done. intros ???. destruct Heq as (HH&_); eapply HH, unique_exists, Hunq2. by right. } - 1,2: eapply tree_access_many_more_active_helper_1; last done; first done; last done; intros ???. - 2: eapply Heq. 1-2: eapply unique_exists, Hunq2; by right. - 1,2: eapply tree_access_many_no_cousins_helper_1; last done; first done; last done; intros ???. - 2: eapply Heq. 1-2: eapply unique_exists, Hunq2; by right. - { done. } - { rewrite /tree_unique. erewrite <- tree_access_many_helper_1. 1: exact Hunq. exact H1. } - Qed. - - Lemma tree_equals_access_all_protected_initialized' tr1 tr1' tr2 cid ev1 ev2 - (Hwf1 : wf_tree tr1) - (Hwf2 : wf_tree tr2) - (PMI : parents_more_init tr2) - (PMA1 : parents_more_active tr1) - (PMA2 : parents_more_active tr2) - (ProtParentsNonDis1 : protected_parents_not_disabled C tr1) - (ProtParentsNonDis2 : protected_parents_not_disabled C tr2) - (NA1 : no_active_cousins C tr1) - (NA2 : no_active_cousins C tr2) - (CC1 : tree_items_compat_nexts tr1 ev1 ev2) - (CC2 : tree_items_compat_nexts tr2 ev1 ev2) : - cid ∈ C → - tree_equal Forwards tr1 tr2 → - tree_access_all_protected_initialized C cid tr1 = Some tr1' → - ∃ tr2', tree_access_all_protected_initialized C cid tr2 = Some tr2' ∧ - tree_equal Forwards tr1' tr2'. - Proof. - intros Hc Heq. - rewrite /tree_access_all_protected_initialized. - erewrite <- (tree_equals_protected_initialized Forwards tr1 tr2); last done. - 2-3: by eapply wf_tree_tree_unique. 2-8: done. - eapply tree_equals_access_many_helper_1. 1-9: done. - {intros tg E. setoid_rewrite elem_of_elements. - intros (it&Hit&_)%tree_all_protected_initialized_elem_of. all: eapply wf_tree_tree_unique; try apply Hwf1. - by eapply lookup_implies_contains. } - Qed. - - Lemma apply_within_trees_lift d trs fn blk trs' : - wf_trees trs → - apply_within_trees fn blk trs = Some trs' → - (∀ tr tr', trs !! blk = Some tr → trs' !! blk = Some tr' → fn tr = Some tr' → tree_equal d tr tr') → - trees_equal d trs trs'. - Proof. - intros Hwf (tr&Htr&(tr'&Htr'&[= <-])%bind_Some)%bind_Some Heq. - intros bb. destruct (decide (bb = blk)) as [<-|Hne]. - - rewrite lookup_insert Htr. econstructor. eapply Heq. 1,3: done. by rewrite lookup_insert. - - rewrite lookup_insert_ne //. destruct (trs !! bb) eqn:HHeq. all: rewrite !HHeq. all: econstructor. - eapply tree_equal_reflexive. eapply wf_tree_tree_item_determined, Hwf, HHeq. - Qed. - - Lemma trees_equal_access_all_protected_initialized trs1 trs1' trs2 cid ev1 ev2 - (Hwf1 : wf_trees trs1) - (Hwf2 : wf_trees trs2) - (PMI : each_tree_parents_more_init trs2) - (PMA1 : each_tree_parents_more_active trs1) - (PMA2 : each_tree_parents_more_active trs2) - (ProtParentsNonDis1 : each_tree_protected_parents_not_disabled C trs1) - (ProtParentsNonDis2 : each_tree_protected_parents_not_disabled C trs2) - (NA1 : each_tree_no_active_cousins C trs1) - (NA2 : each_tree_no_active_cousins C trs2) - (CC1 : trees_compat_nexts trs1 ev1 ev2) - (CC2 : trees_compat_nexts trs2 ev1 ev2) : - cid ∈ C → - trees_equal Forwards trs1 trs2 → - trees_access_all_protected_initialized C cid trs1 = Some trs1' → - ∃ trs2', trees_access_all_protected_initialized C cid trs2 = Some trs2' ∧ - trees_equal Forwards trs1' trs2'. - Proof. - intros Hc Heq Htrapi. - epose proof (trees_access_all_protected_initialized_pointwise_1 _ _ _ _ Htrapi) as Htrapi1. - odestruct (trees_access_all_protected_initialized_pointwise_2 _ trs2) as (trs2'&Htrs2'). - { intros k. destruct (Htrapi1 k) as (HH'&_). intros tr2 Htr2. - specialize (Heq k). rewrite Htr2 in Heq. inversion Heq as [tr1 x1 Heqtr Htr1 e|]. subst x1. - destruct (HH' tr1) as (tr1'&Htr1'&HHtr1'); first done. - edestruct tree_equals_access_all_protected_initialized' as (tr2'&Htr2'&Heq'). - 13: exact Heqtr. 13: exact HHtr1'. 1: by eapply Hwf1. 1: by eapply Hwf2. - 11: by eexists. 1: by eapply PMI. 1: by eapply PMA1. 1: by eapply PMA2. 1: by eapply ProtParentsNonDis1. 1: by eapply ProtParentsNonDis2. - 1: by eapply NA1. 1: by eapply NA2. 1: by eapply CC1. 1: by eapply CC2. done. } - eexists; split; first done. - intros k. specialize (Heq k). - epose proof (trees_access_all_protected_initialized_pointwise_1 _ _ _ _ Htrs2' k) as (Htrapi2A&Htrapi2B). - specialize (Htrapi1 k) as (Htrapi1A&Htrapi1B). - inversion Heq as [tr1 tr2 Heqtr Htr1 Htr2|HNone1 HNone2]; last first. - - rewrite Htrapi1B // Htrapi2B //. econstructor. - - symmetry in Htr1,Htr2. - destruct (Htrapi1A _ Htr1) as (tr1'&Htr1'&Hrapi1'). destruct (Htrapi2A _ Htr2) as (tr2'&Htr2'&Hrapi2'). - rewrite Htr1' Htr2'. econstructor. - edestruct tree_equals_access_all_protected_initialized' as (tr2''&Htr2'u&Htr2'eq). - 14: exact Hrapi1'. 13: exact Heqtr. 1: by eapply Hwf1. 1: by eapply Hwf2. 1: by eapply PMI. 1: by eapply PMA1. 1: by eapply PMA2. 1: by eapply ProtParentsNonDis1. 1: by eapply ProtParentsNonDis2. - 1: by eapply NA1. 1: by eapply NA2. 1: by eapply CC1. 1: by eapply CC2. 1: done. - rewrite Hrapi2' in Htr2'u. injection Htr2'u as <-. done. - Qed. - - (* A bunch of extra conditions on the structure. - They are put in the same clause to simplify this theorem, but we will want - a higher-level lemma that derives these assumptions from their actual justification. *) - Definition tree_equal_asymmetric_read_pre_protected tr range it acc_tg (mode:bool) := - (∀ off, range'_contains range off → - let pp_acc := item_lookup it off in - pp_acc.(initialized) = PermInit ∧ pp_acc.(perm) ≠Disabled ∧ - ∀ tg' it', tree_lookup tr tg' it' → - let pp := item_lookup it' off in - let rd := rel_dec tr tg' acc_tg in (* flipped here so that it's correcty lined up with logical_state *) - match rd with - Foreign (Parent _) => pp.(initialized) = PermInit ∧ pp.(perm) ≠Disabled - | Foreign Cousin => pp.(perm) ≠Active | _ => True end ∧ - if mode then (rd = Child (Strict Immediate) → pp.(perm) = Disabled) else - (pp_acc.(perm) = Frozen ∧ (∀ i, rd = Child (Strict i) → pp.(perm) ≠Active))). - - (* Remember that the entire reason we have [trees_equal] in the first place - is to enable spurious reads. This is the lemma that verifies that after we - do a spurious read we get a [tree_equal]. A companion lemma (stating - that under certain circumstances the spurious read will succeed) will be proved - separately. - - The hypotheses are guided by the optimizations that we want to prove. - We can't (and don't plan to) do spurious reads anywhere, only on protected - tags. For now we require that the tag also doesn't have any Active - children. Both of these can be relaxed slightly, but a more general version - of this lemma will come only if actually required. - - Because we have nice properties of transitivity and reflexivity of [tree_equal] - already, the proof can be simplified by only considering the case where - before the asymmetric read the trees are identical. In other words we're going - to check that a tree is [tree_equal] to itself after a read. *) - Lemma tree_equal_asymmetric_read_protected - {d tr tr' acc_tg range it} (mode:bool) - (GloballyUnique : forall tg, tree_contains tg tr -> tree_unique tg tr) - : - (* Accessed tag must be in the tree and protected*) - tree_lookup tr acc_tg it -> - protector_is_active it.(iprot) C -> - tree_equal_asymmetric_read_pre_protected tr range it acc_tg mode -> - (* Under the above conditions if we do a spurious read and it succeeds - we get a [tree_equal] on the outcome. *) - memory_access AccessRead C acc_tg range tr = Some tr' -> - tree_equal d tr tr'. - Proof. - intros Lkup Protected TreeShapeProper Acc. - split; last split. - { intro tg. eapply access_preserves_tags. eassumption. } - { intros tg1 tg2. eapply access_same_rel_dec. eassumption. } - (* That was the easy part, helped by the fact that our initial configuration - is reflexivity instead of a more general instance of [tree_equal]. - Soon it will get more interesting. *) - intros tg0 Ex. - destruct (unique_implies_lookup (GloballyUnique _ Ex)) as [it0 Lookup0]. - exists it0. - assert (tree_unique tg0 tr') as Unq0'. { - erewrite <- tree_apply_access_preserve_unique; last eassumption. - apply GloballyUnique. assumption. - } - destruct (apply_access_spec_per_node (proj1 Lookup0) (proj2 Lookup0) Acc) as - (it0' & it0'Spec & Ex0' & Det0'). - symmetry in it0'Spec. - exists it0'. - split; first assumption. - split; first (split; assumption). - (* Now down to per-item reasoning *) - intro loc. - split; first (eapply item_apply_access_preserves_metadata; eassumption). - rewrite bind_Some in it0'Spec; destruct it0'Spec as (perms' & perms'Spec & [= <-]). - pose proof (mem_apply_range'_spec _ _ loc _ _ perms'Spec) as PerLoc. - clear perms'Spec. - assert (itag it0 = tg0) by (eapply tree_determined_specifies_tag; eapply Lookup0). - assert (itag it = acc_tg) by (eapply tree_determined_specifies_tag; eapply Lkup). - subst. - (* Finally the reasoning is per-location *) - destruct (decide _) as [HinRange|?]; last first. - { rewrite /item_lookup /= PerLoc. - constructor. } - destruct (TreeShapeProper _ HinRange) as (Htginit&Htgnondis&Hothers). - (* Keep digging until [apply_access_perm_inner] *) - destruct PerLoc as (perm' & perm'Lookup & perm'Spec). - pose proof Hothers as Hothers_pure. - ospecialize (Hothers _ _ Lookup0). - change (default _ _) with (item_lookup it0 loc) in perm'Spec. - rewrite {2}/item_lookup perm'Lookup /=. - rewrite bind_Some in perm'Spec; destruct perm'Spec as (tmperm & Inner & perm'Spec). - rewrite bind_Some in perm'Spec; destruct perm'Spec as (validated & MoreInit & EqPerm). - injection EqPerm; clear EqPerm; intros; subst. - rewrite rel_dec_flip2 in Hothers. - destruct Hothers as (Hothers&Hspecials). - destruct (rel_dec tr (itag it) (itag it0)) as [[]|[]] eqn:Hreldec. - - destruct mode. - + assert (∃ tg, tree_contains tg tr ∧ rel_dec tr tg (itag it) = Child (Strict Immediate) ∧ ParentChildIn tg (itag it0) tr) as (tgsw & Hin & Hswdec&Hpar). - { rewrite /rel_dec in Hreldec. destruct decide as [HP|HnP]; try done. destruct decide as [HP|?]; try done. - destruct HP as [Heq|HSP]. 1: exfalso; eapply HnP; by left. - eapply immediate_sandwich in HSP as HSP2. 2, 3: eapply GloballyUnique. 2: eapply Lkup. - destruct HSP2 as (tsw&Htsw&HPC). exists tsw. - assert (tree_contains tsw tr) as Hcont. - { eapply contains_child. 1: right; by eapply Immediate_is_StrictParentChild. - eapply Lkup. } - split_and!. 1: done. 2: done. - rewrite /rel_dec decide_True. - 2: right; by eapply Immediate_is_StrictParentChild. - rewrite decide_False. 1: by rewrite decide_True. - intros HH. eapply immediate_parent_not_child. 4: exact HH. 3: done. - all: eapply GloballyUnique. 1: eapply Lkup. done. } - assert (∃ itsw, tree_lookup tr tgsw itsw) as (itsw&Hitsw). - 1: eapply unique_implies_lookup, GloballyUnique, Hin. - specialize (Hothers_pure _ _ Hitsw). - destruct (apply_access_spec_per_node (proj1 Hitsw) (proj2 Hitsw) Acc) as - (itsw' & itsw'Spec & Hitsw'). - destruct Hothers_pure as (_&HH). ospecialize (HH _). 1: done. - eapply (perm_eq_up_to_C_disabled_parent _ _ _ _ _ _ tgsw). 3: rewrite /= most_init_comm //=. - * econstructor. 2: done. 1: rewrite /rel_dec decide_True //. - destruct (item_lookup itsw loc) as [[] pp] eqn:HHH; simpl in *; subst pp. - 1: econstructor 1. econstructor 2. econstructor 1. - * econstructor. 1: erewrite <- access_same_rel_dec. 2: eassumption. 1: rewrite /rel_dec decide_True //. - 1: exact Hitsw'. symmetry in itsw'Spec. - eapply bind_Some in itsw'Spec as (psw&Hsw&[= Hitsweq]). - pose proof (mem_apply_range'_spec _ _ loc _ _ Hsw) as PerLocSW. - rewrite decide_True // in PerLocSW. destruct PerLocSW as (p & HPP & Hacc). - rewrite /= /apply_access_perm /apply_access_perm_inner /= in Hacc. - change (default _ _) with (item_lookup itsw loc) in Hacc. - assert (itag itsw = tgsw) as <- by by eapply tree_lookup_correct_tag. - rewrite rel_dec_flip2 Hswdec /= HH /= most_init_comm /= in Hacc. - rewrite /item_lookup /= -Hitsweq HPP /=. - destruct (item_lookup itsw loc) as [ini prm] eqn:Heq; simpl in *; subst prm. - edestruct (bool_decide (protector_is_active (iprot itsw) C)), ini in Hacc; simpl in Hacc; try discriminate Hacc; injection Hacc as <-. - all: try econstructor 1. all: econstructor 2; econstructor 1. - + rewrite /apply_access_perm_inner /= in Inner. rewrite /= most_init_comm /=. - destruct Hspecials as (Hfrz&Hnact). - destruct (item_lookup it0 loc) as [ini [cfl| | | |]] eqn:Hperm. - 2,4,5: by (destruct ini, (bool_decide (protector_is_active (iprot it0) C)); simpl in *; simplify_eq; econstructor 1). - 2: exfalso; by eapply Hnact. - simpl in *. assert (∃ cfl', validated = Reserved cfl') as (cfl'&->). - { destruct ini, cfl, (bool_decide (protector_is_active (iprot it0) C)); simpl in *; eexists; simplify_eq; done. } - destruct (apply_access_spec_per_node (proj1 Lkup) (proj2 Lkup) Acc) as - (it' & it'Spec & Hit'). symmetry in it'Spec. - eapply bind_Some in it'Spec as (pit&Hpit&[= Hiteq]). - pose proof (mem_apply_range'_spec _ _ loc _ _ Hpit) as PerLoc. - rewrite decide_True // in PerLoc. destruct PerLoc as (p & HPP & Hacc). - rewrite /= /apply_access_perm /apply_access_perm_inner /= in Hacc. - change (default _ _) with (item_lookup it loc) in Hacc. - assert (itag it' = itag it) as Hit by by eapply tree_lookup_correct_tag. - rewrite rel_dec_refl Hfrz /= most_init_comm /= in Hacc. - rewrite Tauto.if_same /= in Hacc. injection Hacc as <-. - eapply perm_eq_up_to_C_frozen_parent with (witness_tg := itag it). destruct d. - * econstructor. 1: rewrite rel_dec_flip2 Hreldec //. 1: exact Lkup. 1: done. 1: done. - * econstructor. - { erewrite <- access_same_rel_dec. 2: done. rewrite rel_dec_flip2 Hreldec //. } - { eapply Hit'. } - all: rewrite /item_lookup -Hiteq /= HPP /= //. - - rewrite /= most_init_comm /=. - rewrite /apply_access_perm_inner /= in Inner. - destruct (item_lookup it0 loc) as [[] [[]| | | |]] eqn:Hperm, (bool_decide (protector_is_active (iprot it0) C)) eqn:Hprot; simpl in *. - all: try by (simplify_eq; econstructor 1). - 1-2: simplify_eq; econstructor 2; - [by eapply bool_decide_eq_true_1| |econstructor 1]. - 1-2: eapply (pseudo_conflicted_cousin_init _ _ _ (itag it) it); - [rewrite rel_dec_flip2 Hreldec //|done..]. - - destruct Hothers as (Hinit&Hndis). - rewrite /apply_access_perm_inner /= in Inner. - destruct (item_lookup it0 loc) as [[] pp] eqn:Hperm. 2: done. - assert (pp = tmperm) as ->. - { simpl in *. destruct pp; simplify_eq; done. } - rewrite /= in MoreInit|-*. - destruct tmperm, (bool_decide (protector_is_active (iprot it0) C)); simpl in MoreInit. - all: try done. all: simplify_eq; econstructor 1. - - simpl in *. assert (itag it = itag it0) as Htageq. - { rewrite /rel_dec in Hreldec. do 2 (destruct decide; try done). - eapply mutual_parent_child_implies_equal. 1: done. 1: eapply Lkup. all: done. } - assert (it = it0) as ->. - { eapply tree_determined_unify. 1, 2: eapply Lkup. rewrite Htageq. eapply Lookup0. } - rewrite Htginit in MoreInit|-*. - rewrite bool_decide_true // /= in MoreInit. - destruct (item_lookup it0 loc) as [[] pp] eqn:Hperm. 2: done. - destruct pp; try done. all: repeat (simpl in *; simplify_eq); by econstructor 1. - Qed. - - (* We can also do symmetric writes, provided we have sufficiently strong preconditions, - which include being protected. *) - Definition tree_equal_asymmetric_write_pre_protected tr range it acc_tg := - (∀ off, range'_contains range off → - let pp_acc := item_lookup it off in - pp_acc.(initialized) = PermInit ∧ pp_acc.(perm) = Active ∧ - ∀ tg' it', tree_lookup tr tg' it' → - let pp := item_lookup it' off in - let rd := rel_dec tr tg' acc_tg in (* flipped here so that it's correcty lined up with logical_state *) - match rd with - | Child (Strict Immediate) => pp.(perm) = Disabled - | Child _ => True - | Foreign (Parent _) => pp.(initialized) = PermInit ∧ pp.(perm) = Active (* this follows from state_wf *) - | Foreign Cousin => match pp.(perm) with Disabled => True | ReservedIM => ¬ protector_is_active it'.(iprot) C (* never occurs *) | _ => pp.(initialized) = PermLazy end end). - - Lemma disabled_is_disabled x1 x2 x3 x4 pp : perm pp = Disabled → is_disabled x1 x2 x3 pp x4. - Proof. - destruct pp as [[] pp]; simpl; intros ->. - 1: econstructor 1. - econstructor 2. econstructor 1. - Qed. - - Lemma tree_equal_asymmetric_write_protected - {d tr tr' acc_tg range it} - (GloballyUnique : forall tg, tree_contains tg tr -> tree_unique tg tr) - : - (* Accessed tag must be in the tree and protected*) - tree_lookup tr acc_tg it -> - protector_is_active it.(iprot) C -> - tree_equal_asymmetric_write_pre_protected tr range it acc_tg -> - (* Under the above conditions if we do a spurious read and it succeeds - we get a [tree_equal] on the outcome. *) - memory_access AccessWrite C acc_tg range tr = Some tr' -> - tree_equal d tr tr'. - Proof. - intros Lkup Protected TreeShapeProper Acc. - split; last split. - { intro tg. eapply access_preserves_tags. eassumption. } - { intros tg1 tg2. eapply access_same_rel_dec. eassumption. } - (* That was the easy part, helped by the fact that our initial configuration - is reflexivity instead of a more general instance of [tree_equal]. - Soon it will get more interesting. *) - intros tg0 Ex. - destruct (unique_implies_lookup (GloballyUnique _ Ex)) as [it0 Lookup0]. - exists it0. - assert (tree_unique tg0 tr') as Unq0'. { - erewrite <- tree_apply_access_preserve_unique; last eassumption. - apply GloballyUnique. assumption. - } - destruct (apply_access_spec_per_node (proj1 Lookup0) (proj2 Lookup0) Acc) as - (it0' & it0'Spec & Ex0' & Det0'). - symmetry in it0'Spec. - exists it0'. - split; first assumption. - split; first (split; assumption). - (* Now down to per-item reasoning *) - intro loc. - split; first (eapply item_apply_access_preserves_metadata; eassumption). - rewrite bind_Some in it0'Spec; destruct it0'Spec as (perms' & perms'Spec & [= <-]). - pose proof (mem_apply_range'_spec _ _ loc _ _ perms'Spec) as PerLoc. - clear perms'Spec. - assert (itag it0 = tg0) by (eapply tree_determined_specifies_tag; eapply Lookup0). - assert (itag it = acc_tg) by (eapply tree_determined_specifies_tag; eapply Lkup). - subst. - (* Finally the reasoning is per-location *) - destruct (decide _) as [HinRange|?]; last first. - { rewrite /item_lookup /= PerLoc. - constructor. } - destruct (TreeShapeProper _ HinRange) as (Htginit&Htgactive&Hothers). - (* Keep digging until [apply_access_perm_inner] *) - destruct PerLoc as (perm' & perm'Lookup & perm'Spec). - pose proof Hothers as Hothers_pure. - ospecialize (Hothers _ _ Lookup0). - change (default _ _) with (item_lookup it0 loc) in perm'Spec. - rewrite {2}/item_lookup perm'Lookup /=. - rewrite bind_Some in perm'Spec; destruct perm'Spec as (tmperm & Inner & perm'Spec). - rewrite bind_Some in perm'Spec; destruct perm'Spec as (validated & MoreInit & EqPerm). - injection EqPerm; clear EqPerm; intros; subst. - rewrite rel_dec_flip2 /= in Hothers. - destruct (rel_dec tr (itag it) (itag it0)) as [[]|[]] eqn:Hreldec; simpl in Hothers. - - assert (∃ tg, tree_contains tg tr ∧ rel_dec tr tg (itag it) = Child (Strict Immediate) ∧ ParentChildIn tg (itag it0) tr) as (tgsw & Hin & Hswdec&Hpar). - { rewrite /rel_dec in Hreldec. destruct decide as [HP|HnP]; try done. destruct decide as [HP|?]; try done. - destruct HP as [Heq|HSP]. 1: exfalso; eapply HnP; by left. - eapply immediate_sandwich in HSP as HSP2. 2, 3: eapply GloballyUnique. 2: eapply Lkup. - destruct HSP2 as (tsw&Htsw&HPC). exists tsw. - assert (tree_contains tsw tr) as Hcont. - { eapply contains_child. 1: right; by eapply Immediate_is_StrictParentChild. - eapply Lkup. } - split_and!. 1: done. 2: done. - rewrite /rel_dec decide_True. - 2: right; by eapply Immediate_is_StrictParentChild. - rewrite decide_False. 1: by rewrite decide_True. - intros HH. eapply immediate_parent_not_child. 4: exact HH. 3: done. - all: eapply GloballyUnique. 1: eapply Lkup. done. } - assert (∃ itsw, tree_lookup tr tgsw itsw) as (itsw&Hitsw). - 1: eapply unique_implies_lookup, GloballyUnique, Hin. - specialize (Hothers_pure _ _ Hitsw). - destruct (apply_access_spec_per_node (proj1 Hitsw) (proj2 Hitsw) Acc) as - (itsw' & itsw'Spec & Hitsw'). rewrite Hswdec /= in Hothers_pure. - eapply (perm_eq_up_to_C_disabled_parent _ _ _ _ _ _ tgsw). 3: rewrite /= most_init_comm //=. - * econstructor. 2: done. 1: rewrite /rel_dec decide_True //. eapply disabled_is_disabled, Hothers_pure. - * econstructor. 1: erewrite <- access_same_rel_dec. 2: eassumption. 1: rewrite /rel_dec decide_True //. - 1: exact Hitsw'. symmetry in itsw'Spec. - eapply bind_Some in itsw'Spec as (psw&Hsw&[= Hitsweq]). - pose proof (mem_apply_range'_spec _ _ loc _ _ Hsw) as PerLocSW. - rewrite decide_True // in PerLocSW. destruct PerLocSW as (p & HPP & Hacc). - rewrite /= /apply_access_perm /apply_access_perm_inner /= in Hacc. - change (default _ _) with (item_lookup itsw loc) in Hacc. - assert (itag itsw = tgsw) as <- by by eapply tree_lookup_correct_tag. - rewrite rel_dec_flip2 Hswdec /= Hothers_pure /= in Hacc. - rewrite /item_lookup /= -Hitsweq HPP /=. - repeat (case_match; simpl in *; try done; simplify_eq). - all: by eapply disabled_is_disabled. - - rewrite /= most_init_comm /=. - rewrite /apply_access_perm_inner /= in Inner. - eapply rel_dec_flip in Hreldec. - destruct (item_lookup it0 loc) as [[] [[]| | | |]] eqn:Hperm, (bool_decide (protector_is_active (iprot it0) C)) eqn:Hprot; simpl in *. - all: try by (simplify_eq; first [done | econstructor 1]). - all: try by eapply bool_decide_eq_true_1 in Hprot. - all: injection Inner as <-; injection MoreInit as <-. - all: econstructor 4; last econstructor 1. - all: econstructor 2; [exact Hreldec|exact Lkup|done|destruct (item_lookup it loc); simpl in *; congruence| ]. - all: intros [=]. all: by eapply bool_decide_eq_true_1. - - destruct Hothers as (Hini&Hact). - rewrite /apply_access_perm_inner /= in Inner. - destruct (item_lookup it0 loc) as [ini pp] eqn:Hperm. - simpl in Hini, Hact. subst ini pp. simpl in Inner. simplify_eq. simpl in MoreInit. - destruct (bool_decide (protector_is_active (iprot it0) C)); simpl in MoreInit|-*; simplify_eq. - all: econstructor 1. - - simpl in *. assert (itag it = itag it0) as Htageq. - { rewrite /rel_dec in Hreldec. do 2 (destruct decide; try done). - eapply mutual_parent_child_implies_equal. 1: done. 1: eapply Lkup. all: done. } - assert (it = it0) as ->. - { eapply tree_determined_unify. 1, 2: eapply Lkup. rewrite Htageq. eapply Lookup0. } - rewrite Htginit in MoreInit|-*. rewrite Htgactive in Inner. simplify_eq. - rewrite bool_decide_true // /= in MoreInit. simplify_eq. - destruct (item_lookup it0 loc) as [ii pp]. simpl in *; subst ii pp. econstructor 1. - Qed. - - Lemma rel_dec_equal_ParentChildIn_equiv tr1 tr2 : - (∀ tg, tree_contains tg tr1 ↔ tree_contains tg tr2) → - (∀ tg1 tg2, rel_dec tr1 tg1 tg2 = rel_dec tr2 tg1 tg2) → - ∀ tg1 tg2, (ParentChildIn tg1 tg2 tr1 ↔ ParentChildIn tg1 tg2 tr2) ∧ (ImmediateParentChildIn tg1 tg2 tr1 ↔ ImmediateParentChildIn tg1 tg2 tr2). - Proof. - intros Hcont H tg1 tg2. - specialize (H tg2 tg1). - rewrite /rel_dec in H. destruct (decide (ParentChildIn tg1 tg2 tr1)) as [H1|H1]; last first. - all: destruct (decide (ParentChildIn tg1 tg2 tr2)) as [H2|H2]; try done. - all: split; first tauto. - - split; intros H3%Immediate_is_StrictParentChild; exfalso. 1: eapply H1. 2: eapply H2. all: by right. - - destruct (decide (tree_contains tg1 tr1)) as [Hin|Hnin]; last first. - { split; intros _; eapply ImmediateParentChildIn_parent_not_in; last done. - by setoid_rewrite <- Hcont. } - destruct (decide (tg1 = tg2)) as [->|Hne]. - { split; intros H3%Immediate_is_StrictParentChild; exfalso; (eapply strict_parent_self_impossible; last done). - 2: rewrite <- Hcont. all: done. } - destruct H1 as [?|H1]; first done. - destruct H2 as [?|H2]; first done. - rewrite decide_False in H. 2: { intros [?|H3]; first done. eapply strict_parent_self_impossible; first done. by eapply StrictParentChild_transitive. } - rewrite (decide_False This) in H. 2: { intros [?|H3]; first done. setoid_rewrite Hcont in Hin. eapply strict_parent_self_impossible; first done. by eapply StrictParentChild_transitive. } - destruct (decide (ImmediateParentChildIn tg1 tg2 tr1)), (decide (ImmediateParentChildIn tg1 tg2 tr2)); done. - Qed. - - Lemma rel_dec_equal_ParentChildIn_equiv_lift tr1 tr2 : - (∀ tg, tree_contains tg tr1 ↔ tree_contains tg tr2) → - (∀ tg1 tg2, rel_dec tr1 tg1 tg2 = rel_dec tr2 tg1 tg2) → - (∀ tg1 tg2, ParentChildIn tg1 tg2 tr1 ↔ ParentChildIn tg1 tg2 tr2) ∧ - (∀ tg1 tg2, StrictParentChildIn tg1 tg2 tr1 ↔ StrictParentChildIn tg1 tg2 tr2) ∧ - (∀ tg1 tg2, ImmediateParentChildIn tg1 tg2 tr1 ↔ ImmediateParentChildIn tg1 tg2 tr2). - Proof. - intros H1 H2. - epose proof (rel_dec_equal_ParentChildIn_equiv _ _ H1 H2) as H. split_and!. - 1, 3: eapply H. - intros tg1 tg2. - destruct (decide (tree_contains tg1 tr1)) as [H3|H3]; last first. - all: epose proof H3 as H3'; setoid_rewrite H1 in H3'. - { split; intros _; rewrite /StrictParentChildIn; eapply every_subtree_eqv_universal. - all: intros br Hex Htg; exfalso. 1: eapply H3'. 2: eapply H3. - all: eapply exists_node_iff_exists_root. - all: eapply exists_subtree_eqv_existential; eexists. - all: split; first done; done. - all: split; first eapply exists_node_iff_exists_root. } - destruct (decide (tg1 = tg2)) as [->|Hne]. - { split; intros []%strict_parent_self_impossible; done. } - destruct (H tg1 tg2) as ((HH1&HH2)&_). - split; intros Hc. - - destruct HH1 as [?|HH1]; try done. by right. - - destruct HH2 as [?|HH2]; try done. by right. - Qed. - - Lemma tree_equal_create_child d tr1 tr2 tr1' tg_new tg_old pk im rk cid ev2 : - wf_tree tr1 → wf_tree tr2 → - tree_items_compat_nexts tr1 tg_new ev2 → tree_items_compat_nexts tr2 tg_new ev2 → - (cid < ev2)%nat → - tree_contains tg_old tr1 → - ¬ tree_contains tg_new tr1 → - tree_equal d tr1 tr2 → - create_child C tg_old tg_new pk im rk cid tr1 = Some tr1' → - ∃ tr2', create_child C tg_old tg_new pk im rk cid tr2 = Some tr2' ∧ - tree_equal d tr1' tr2'. - Proof. - intros Hwf1 Hwf2 Hiwf1 Hiwf2 Hcidwf. - intros Hcontains1 Hnotcont1 (H1&H2&H3) (it_new&Hit_new&[= <-])%bind_Some. - assert (itag it_new = tg_new) as Htgnew by by eapply new_item_has_tag. - assert (tg_old ≠tg_new) as Htgsne by (intros ->; firstorder). - pose proof Hcontains1 as Hcontains2. setoid_rewrite H1 in Hcontains2. - pose proof Hnotcont1 as Hnotcont2. setoid_rewrite H1 in Hnotcont2. - epose proof create_new_item_wf _ _ _ _ _ _ _ Hcidwf Hit_new as Hitemwf. - opose proof (insert_child_wf C _ _ _ _ _ _ _ _ _ _ Hitemwf Hit_new _ Hiwf1 Hwf1) as (_&Hwf1'). - 1: rewrite /create_child Hit_new //. - opose proof (insert_child_wf C _ _ _ _ _ _ _ _ _ _ Hitemwf Hit_new _ Hiwf2 Hwf2) as (_&Hwf2'). - 1: rewrite /create_child Hit_new //. - eexists. split. - 1: rewrite /create_child Hit_new //. - pose proof (rel_dec_equal_ParentChildIn_equiv_lift _ _ H1 H2) as (H2A&H2B&H2C). - split_and!. - - intros tg. destruct (decide (tg = tg_new)) as [->|Hne]. - + split; (intros _; eapply insert_true_produces_exists; [done|]); assumption. - + split; (intros H%insert_false_infer_exists; last congruence); eapply insert_preserves_exists, H1, H. - - eapply same_parent_childs_agree; intros tg tg'. - + destruct (decide (tg = tg_new)) as [->|Hne], (decide (tg' = tg_new)) as [->|Hne']. - * split; intros _; by left. - * subst tg_new. split; (intros [|Hc]; first done); exfalso; (eapply inserted_not_strict_parent; [| |exact Hc]; done). - * subst tg_new. destruct (decide (tg = tg_old)) as [->|Hneold]. - 1: split; intros _; eapply insert_produces_ParentChild; done. - split; (intros [|Hc]; first done). - all: eapply insert_produces_minimal_ParentChild in Hc; [|done..]. - all: eapply ParentChild_transitive; last by eapply insert_produces_ParentChild. - all: right; setoid_rewrite <- insert_eqv_strict_rel; [|done..]. - 1: by setoid_rewrite <- H2B. 1: by setoid_rewrite H2B. - * subst tg_new. split; (intros [->|Hc]; [by left|right]). - all: setoid_rewrite <- insert_eqv_strict_rel; [|done..]. - all: eapply H2B. - all: setoid_rewrite -> insert_eqv_strict_rel; first done; done. - + destruct (decide (tg = tg_new)) as [->|Hne], (decide (tg' = tg_new)) as [->|Hne']. - * subst tg_new. split; intros H; exfalso; (eapply immediate_parent_child_not_equal; [..|done|done]). - 1-2: eapply Hwf1'. 3-4: eapply Hwf2'. - all: eapply insert_true_produces_exists; first done; done. - * subst tg_new. split; (intros Hc%Immediate_is_StrictParentChild); exfalso; (eapply inserted_not_strict_parent; [| |exact Hc]; done). - * subst tg_new. destruct (decide (tg = tg_old)) as [->|Hneold]. - 1: split; intros _; eapply insert_produces_ImmediateParentChild; done. - destruct (decide (tree_contains tg tr1)) as [Htgin|Htgnin]; last first. - { split; intros _; eapply ImmediateParentChildIn_parent_not_in. - all: intros Hc%remove_false_preserves_exists; last done. - all: eapply Htgnin. 1: eapply H1. all: eapply Hc. } - split; intros Hc; exfalso. - all: eapply ImmediateParentChild_of_insert_is_parent in Hc; [done|done|..|done]. - 1: done. by eapply H1. - * subst tg_new. setoid_rewrite <- insert_eqv_imm_rel. 1: apply H2C. - all: done. - - intros tg Hcont. subst tg_new. - destruct (decide (tg = itag it_new)) as [->|Hne]. - { exists it_new, it_new. split_and!. - 1-2: split; first by eapply insert_true_produces_exists. - 1-2: by eapply inserted_determined. - eapply item_eq_up_to_C_reflexive. } - eapply remove_false_preserves_exists in Hcont. 2: done. - destruct (H3 tg Hcont) as (it1&it2&Hlu1&Hlu2&Hequptoc). - exists it1, it2. split_and!. - 1-2: destruct Hlu1, Hlu2. - 1-2: split; first by eapply insert_preserves_exists. - 1-2: setoid_rewrite <- insert_true_preserves_every; done. - intros l. specialize (Hequptoc l) as (Heq1&Heq2). - split; first done. - inversion Heq2 as [|pi c1 c2 Hi1 Hi2 Hi3 Hi4 Hi5| |p1 p2 Hi2 Hi3 Hi4 Hi5|witness_tg ? ? Dis1 Dis2|??? witness_tg Frz1|p1 p2 ini Hd]; simplify_eq. - + by econstructor 1. - + destruct Hlu1 as (Hlu1A&Hlu1B), Hlu2 as (Hlu2A&Hlu2B). - pose proof Hcont as Hcont2. setoid_rewrite H1 in Hcont2. econstructor 2. 1: done. - * inversion Hi2 as [|tg_cs it_cs Hii1 Hii2 Hii3 Hii4 Hii5 Hii6]; simplify_eq; first by econstructor 1. - destruct Hii2 as [HA HB]. - econstructor 2. 3-5: done. - 2: { split. 1: by eapply insert_preserves_exists. - setoid_rewrite <- insert_true_preserves_every; first done. - intros <-. done. } - rewrite /rel_dec in Hii1|-*. - destruct (decide (ParentChildIn tg_cs tg tr1)) as [|HnPC]; first done. - destruct (decide (ParentChildIn tg tg_cs tr1)) as [|HnPC2]; first done. - rewrite decide_False; first rewrite decide_False //; last first. - -- intros [|Hc]; eapply HnPC; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - -- intros [|Hc]; eapply HnPC2; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - * inversion Hi3 as [|tg_cs it_cs Hii1 Hii2 Hii3 Hii4 Hii5 Hii6]; simplify_eq; first by econstructor 1. - destruct Hii2 as [HA HB]. - econstructor 2. 3-5: done. - 2: { split. 1: by eapply insert_preserves_exists. - setoid_rewrite <- insert_true_preserves_every; first done. - intros <-. done. } - rewrite /rel_dec in Hii1|-*. - destruct (decide (ParentChildIn tg_cs tg tr2)) as [|HnPC]; first done. - destruct (decide (ParentChildIn tg tg_cs tr2)) as [|HnPC2]; first done. - rewrite decide_False; first rewrite decide_False //; last first. - -- intros [|Hc]; eapply HnPC; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - -- intros [|Hc]; eapply HnPC2; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - + by econstructor 3. - + destruct Hlu1 as (Hlu1A&Hlu1B), Hlu2 as (Hlu2A&Hlu2B). - pose proof Hcont as Hcont2. setoid_rewrite H1 in Hcont2. econstructor 4. - * inversion Hi2 as [|tg_cs it_cs X1 X2 Hii1 Hii2 Hii3 Hii4]; simplify_eq; first by econstructor 1. - destruct Hii2 as [HA HB]. - econstructor 2. 3-5: done. - 2: { split. 1: by eapply insert_preserves_exists. - setoid_rewrite <- insert_true_preserves_every; first done. - intros <-. done. } - rewrite /rel_dec in Hii1|-*. - destruct (decide (ParentChildIn tg_cs tg tr1)) as [|HnPC]; first done. - destruct (decide (ParentChildIn tg tg_cs tr1)) as [|HnPC2]; first done. - rewrite decide_False; first rewrite decide_False //; last first. - -- intros [|Hc]; eapply HnPC; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - -- intros [|Hc]; eapply HnPC2; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - * inversion Hi3 as [|tg_cs it_cs X1 X2 Hii1 Hii2 Hii3 Hii4]; simplify_eq; first by econstructor 1. - destruct Hii2 as [HA HB]. - econstructor 2. 3-5: done. - 2: { split. 1: by eapply insert_preserves_exists. - setoid_rewrite <- insert_true_preserves_every; first done. - intros <-. done. } - rewrite /rel_dec in Hii1|-*. - destruct (decide (ParentChildIn tg_cs tg tr2)) as [|HnPC]; first done. - destruct (decide (ParentChildIn tg tg_cs tr2)) as [|HnPC2]; first done. - rewrite decide_False; first rewrite decide_False //; last first. - -- intros [|Hc]; eapply HnPC; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - -- intros [|Hc]; eapply HnPC2; first by left. right. - eapply insert_eqv_strict_rel; last exact Hc. - 1-2: by intros <-. - + econstructor 5. - * eapply disabled_in_practice_create_child_irreversible. - 5: rewrite /create_child; erewrite Hit_new; done. - -- lia. - -- inversion Dis1 as [it_witness ?? LuWitness]. - pose proof (tree_determined_specifies_tag _ _ _ (proj1 LuWitness) (proj2 LuWitness)) as itag_witness_spec. - pose proof ((proj1 (every_node_iff_every_lookup (wf_tree_tree_item_determined _ Hwf1)) Hiwf1 witness_tg it_witness ltac:(assumption)).(item_tag_valid _ _ _) witness_tg itag_witness_spec). - enough (itag it_new ≠witness_tg) by eassumption. - lia. - -- eassumption. - -- eassumption. - * eapply disabled_in_practice_create_child_irreversible. - 5: rewrite /create_child; erewrite Hit_new; done. - -- lia. - -- inversion Dis1 as [it_witness ?? LuWitness]. - pose proof (tree_determined_specifies_tag _ _ _ (proj1 LuWitness) (proj2 LuWitness)) as itag_witness_spec. - pose proof ((proj1 (every_node_iff_every_lookup (wf_tree_tree_item_determined _ Hwf1)) Hiwf1 witness_tg it_witness ltac:(assumption)).(item_tag_valid _ _ _) witness_tg itag_witness_spec). - enough (itag it_new ≠witness_tg) by eassumption. - lia. - -- eassumption. - -- eassumption. - * auto. - + econstructor 6; destruct d. - * eapply frozen_in_practice_create_child_irreversible. - 4: rewrite /create_child; erewrite Hit_new; done. - -- lia. - -- inversion Frz1 as [it_witness ?? LuWitness]. - pose proof (tree_determined_specifies_tag _ _ _ (proj1 LuWitness) (proj2 LuWitness)) as itag_witness_spec. - pose proof ((proj1 (every_node_iff_every_lookup (wf_tree_tree_item_determined _ Hwf1)) Hiwf1 witness_tg it_witness ltac:(assumption)).(item_tag_valid _ _ _) witness_tg itag_witness_spec). - enough (itag it_new ≠witness_tg) by eassumption. - lia. - -- eassumption. - * eapply frozen_in_practice_create_child_irreversible. - 4: rewrite /create_child; erewrite Hit_new; done. - -- lia. - -- inversion Frz1 as [it_witness ?? LuWitness]. - pose proof (tree_determined_specifies_tag _ _ _ (proj1 LuWitness) (proj2 LuWitness)) as itag_witness_spec. - pose proof ((proj1 (every_node_iff_every_lookup (wf_tree_tree_item_determined _ Hwf2)) Hiwf2 witness_tg it_witness ltac:(assumption)).(item_tag_valid _ _ _) witness_tg itag_witness_spec). - enough (itag it_new ≠witness_tg) by eassumption. - lia. - -- eassumption. - + econstructor 7. done. - Qed. - - Lemma trees_equal_create_child d trs1 trs2 trs1' blk tg_new tg_old pk im rk cid nxtc : - wf_trees trs1 → wf_trees trs2 → - trees_compat_nexts trs1 tg_new nxtc → trees_compat_nexts trs2 tg_new nxtc → - (cid < nxtc)%nat → - trees_contain tg_old trs1 blk → - ¬ trees_contain tg_new trs1 blk → - trees_equal d trs1 trs2 → - apply_within_trees (create_child C tg_old tg_new pk im rk cid) blk trs1 = Some trs1' → - ∃ trs2', apply_within_trees (create_child C tg_old tg_new pk im rk cid) blk trs2 = Some trs2' ∧ - trees_equal d trs1' trs2'. - Proof. - intros Hwf1 Hwf2 Hiwf1 Hiwf2 Hcidwf Hcont Hncont Heq. - intros (tr1&Htr1&(tr1'&Htr1'&[= <-])%bind_Some)%bind_Some. - eapply bind_Some in Htr1' as HH. destruct HH as (it&Hit&[= Htrit]). - epose proof (Heq blk) as HeqblkI. - inversion HeqblkI as [t1x tr2 Heqblk Heq1x Htr2|]; simplify_eq; last congruence. - symmetry in Htr2. assert (t1x = tr1) as -> by congruence. clear Heq1x. - eapply tree_equal_create_child in Htr1' as (tr2'&Htr2'&Heqtr). - - eexists. rewrite /apply_within_trees /= Htr2 /=. - split; first by rewrite /create_child Hit. - intros blk'. destruct (decide (blk = blk')) as [->|Hne]. - + rewrite !lookup_insert. econstructor. - eapply bind_Some in Htr2' as HH. destruct HH as (it2&Hit2&[= <-]). - enough (it = it2) as -> by by eapply Heqtr. - congruence. - + rewrite !lookup_insert_ne //. - - by eapply Hwf1. - - by eapply Hwf2. - - by eapply Hiwf1. - - by eapply Hiwf2. - - done. - - by rewrite /trees_contain /trees_at_block Htr1 in Hcont. - - by rewrite /trees_contain /trees_at_block Htr1 in Hncont. - - done. - Qed. - - Lemma perm_eq_up_to_C_trans {tr1 tr2 tr3 tg l cid perm1 perm2 perm3} : - protected_parents_not_disabled C tr2 → - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - (∀ tg, tree_contains tg tr1 → tree_unique tg tr1) → - parents_more_active tr2 → - no_active_cousins C tr2 → - parents_more_active tr1 → - no_active_cousins C tr1 → - tree_equal Forwards tr1 tr2 → - tree_equal Forwards tr2 tr3 → - perm_eq_up_to_C tr1 tr2 tg l cid Forwards perm1 perm2 → - perm_eq_up_to_C tr2 tr3 tg l cid Forwards perm2 perm3 → - perm_eq_up_to_C tr1 tr3 tg l cid Forwards perm1 perm3. - Proof. - intros Hpnd Hunq1 Hunq2 Hpma1 Hnac1 Hpma2 Hnac2 Heq12 Heq23 EqC1 EqC2. - inversion EqC1 as [pp1|ini1 confl1 confl2 Hprot HP1 HP2|ini1 confl1 confl2 HnoProt|p1 p2 HP1 HP2|wit_tg lp1 lp2 Hdip1 Hdip2 Hini|ini1 confl1 confl2 wit_tg HF|p1 p2 ini Hd]; simplify_eq; - inversion EqC2 as [pp1'|ini1' confl1' confl2' Hprot' HP1' HP2'|ini1' confl1' confl2' HnoProt'|p1' p2' HP1' HP2'|wit_tg' lp1 lp2 Hdip1' Hdip2' Hini'|ini1' confl1' confl2' wit_tg' HF'|p1' p2' ini' Hd']; simplify_eq. - (* easy case: perm1 = perm2 *) - + econstructor 1. - + econstructor 2. 1: done. 2: done. - eapply tree_equal_transfer_pseudo_conflicted. 1: done. 1: done. 1: done. - 1: by eapply tree_equal_sym. done. - + by econstructor 3. - + econstructor 4. 2: done. - eapply tree_equal_transfer_pseudo_disabled. 5: done. all: done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. congruence. - + eapply trees_equal_transfer_frozen_in_practice_many in HF' as [(Hfip&Hfip2)|(tr&Hdi9p&Hdip2)]. 3-5: eassumption. - * econstructor 6. all: edestruct Hfip2 as (px&Hpx&Hrz). 1: by eapply tree_equal_sym. - enough (px = Frozen) as -> by done. destruct Hrz as [->|(->&[=])]; tauto. - * econstructor 5; last done. all: eapply Hdip2. 2: done. 1: by eapply tree_equal_sym. - + econstructor 7. apply Hd'. - (* case 2: perm1 and perm2 are pseudo_conflicted Reserved *) - + econstructor 2. 1: done. 1: done. - eapply tree_equal_transfer_pseudo_conflicted. 5: exact HP2. all: done. - + econstructor 2; done. - + exfalso. done. - + econstructor 4. 2: done. - eapply conflicted_transfer_pseudo_disabled. - eapply tree_equal_transfer_pseudo_disabled. 4: done. all: done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor 5. 1: exact Hw1. 1: exact Hw3. simpl in *. eapply Hini'. - + eapply trees_equal_transfer_frozen_in_practice_many in HF' as [(Hfip&Hfip2)|(tr&Hdi9p&Hdip2)]. 3-5: eassumption. - * econstructor 6. all: edestruct Hfip2 as (px&Hpx&Hrz). 1: by eapply tree_equal_sym. - enough (px = Frozen) as -> by done. destruct Hrz as [->|(->&[=])]; tauto. - * econstructor 5; last done. all: eapply Hdip2. 2: done. 1: by eapply tree_equal_sym. - + inversion Hd'; simplify_eq. destruct confl1; last econstructor 1. - econstructor 7; econstructor; done. - (* case 3: perm1 and perm2 are unprotected reserved *) - + by econstructor 3. - + exfalso. done. - + by econstructor 3. - + econstructor 4. 2: done. - eapply conflicted_transfer_pseudo_disabled. - eapply tree_equal_transfer_pseudo_disabled. 4: done. all: done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + by econstructor 3. - + inversion Hd'; simplify_eq; done. - (* case 4: perm1 and perm2 are pseudo-disabled *) - + econstructor 4. 1: done. - eapply tree_equal_transfer_pseudo_disabled. 5: by eapply tree_equal_sym. all: done. - + econstructor 4. 1: done. - eapply conflicted_transfer_pseudo_disabled. - eapply tree_equal_transfer_pseudo_disabled. 5: by eapply tree_equal_sym. all: done. - + econstructor 4. 1: done. - eapply conflicted_transfer_pseudo_disabled. - eapply tree_equal_transfer_pseudo_disabled. 5: by eapply tree_equal_sym. all: done. - + econstructor 4. all: done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + econstructor 4. 1: done. - eapply conflicted_transfer_pseudo_disabled. - eapply tree_equal_transfer_pseudo_disabled. 5: by eapply tree_equal_sym. all: done. - + econstructor 4. 1: done. - eapply transfer_pseudo_disabled_notimm. - 1: eapply tree_equal_transfer_pseudo_disabled. 5: by eapply tree_equal_sym. 1-4: done. - all: inversion Hd'; done. - (* case 5: perm1 and perm2 are disabled in practice *) - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. congruence. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - (* case 6: perm1 and perm2 are frozen in practice. *) - + by econstructor 6. - + by econstructor 6. - + by econstructor 6. - + econstructor 4. 2: done. - eapply transfer_pseudo_disabled_notimm. - 1: eapply tree_equal_transfer_pseudo_disabled. 5: done. 1-4: done. - all: done. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + by econstructor 6. - + inversion Hd'; try done. - simplify_eq. destruct confl1. 2: econstructor 1. - econstructor 7. econstructor. done. - (* case 7: the asymmetric case *) - + by econstructor 7. - + inversion Hd; simplify_eq. econstructor 2; try done. econstructor 1. - + inversion Hd; simplify_eq. done. - + econstructor 4. 2: done. - eapply transfer_pseudo_disabled_notimm. - 1: eapply tree_equal_transfer_pseudo_disabled. 5: done. 1-4: done. - all: by inversion Hd. - + odestruct (trees_equal_transfer_disabled_in_practice_twice Hunq1 Hpma1 Hnac1 Heq12 Heq23) as (ww&Hw1&Hw2&Hw3). - 1: done. econstructor. 1: exact Hw1. 1: exact Hw3. simpl in *. done. - + eapply trees_equal_transfer_frozen_in_practice_many in HF' as [(Hfip&Hfip2)|(tr&Hdi9p&Hdip2)]. 3-5: eassumption. - * inversion Hd; simplify_eq. econstructor 6. - all: edestruct Hfip2 as (px&Hpx&Hrz). 1: by eapply tree_equal_sym. - enough (px = Frozen) as -> by done. destruct Hrz as [->|(->&[=])]; tauto. - * econstructor 5; last done. all: eapply Hdip2. 2: done. 1: by eapply tree_equal_sym. - + inversion Hd; inversion Hd'; by simplify_eq. - Qed. - - Lemma item_eq_up_to_C_trans {tr1 tr2 tr3 tg it1 it2 it3} : - protected_parents_not_disabled C tr2 → - (∀ tg, tree_contains tg tr1 → tree_unique tg tr1) → - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr1 → - parents_more_active tr2 → - no_active_cousins C tr1 → - no_active_cousins C tr2 → - tree_equal Forwards tr1 tr2 → - tree_equal Forwards tr2 tr3 → - item_eq_up_to_C tr1 tr2 tg Forwards it1 it2 → - item_eq_up_to_C tr2 tr3 tg Forwards it2 it3 → - item_eq_up_to_C tr1 tr3 tg Forwards it1 it3. - Proof. - intros Hnd ?????? He1 He2 H1 H2 l. - destruct (H1 l) as (H1l&H1r), (H2 l) as (H2l&H2r). - split; first congruence. - eapply perm_eq_up_to_C_trans. 1-9: done. - 1: exact H1r. rewrite H1l. 1: exact H2r. - Qed. - - - Lemma tree_equal_trans tr1 tr2 tr3 : - protected_parents_not_disabled C tr2 → - (∀ tg, tree_contains tg tr1 → tree_unique tg tr1) → - (∀ tg, tree_contains tg tr2 → tree_unique tg tr2) → - parents_more_active tr1 → - parents_more_active tr2 → - no_active_cousins C tr1 → - no_active_cousins C tr2 → - tree_equal Forwards tr1 tr2 → - tree_equal Forwards tr2 tr3 → - tree_equal Forwards tr1 tr3. - Proof. - rewrite /tree_equal. - intros ??????? [SameTg1 [SameRel1 EqC1]] [SameTg2 [SameRel2 EqC2]]. - split; [|split]. - + intro tg. rewrite SameTg1 SameTg2 //. - + intros tg tg'. rewrite SameRel1 SameRel2 //. - + intros tg Ex. - destruct (EqC1 _ Ex) as (it1M&it2M&Hlu1M&Hlu2M&Hiteq). - destruct (EqC2 tg) as (it1R&it2R&Hlu1R&Hlu2R&Hiteq2). - 1: by eapply Hlu2M. - assert (it2M = it1R) as -> by by eapply tree_lookup_unique. - exists it1M, it2R. split_and!; [done..|]. - eapply item_eq_up_to_C_trans; done. - Qed. - - Lemma trees_equal_trans trs1 trs2 trs3 : - each_tree_protected_parents_not_disabled C trs2 → - wf_trees trs1 → - wf_trees trs2 → - each_tree_parents_more_active trs1 → - each_tree_parents_more_active trs2 → - each_tree_no_active_cousins C trs1 → - each_tree_no_active_cousins C trs2 → - trees_equal Forwards trs1 trs2 → - trees_equal Forwards trs2 trs3 → - trees_equal Forwards trs1 trs3. - Proof. - rewrite /trees_equal. - intros Hu1 Hu2 Hu3 Hu4 Hu5 Hu6 Hu7 Equals1 Equals2 blk. - specialize (Equals1 blk). specialize (Equals2 blk). - destruct (trs1 !! blk) as [tr1|] eqn:Heq1; - destruct (trs2 !! blk) as [tr2|] eqn:Heq2; - destruct (trs3 !! blk) as [tr3|] eqn:Heq3. - all: inversion Equals1; inversion Equals2; simplify_eq; first [exfalso; congruence | econstructor]. - eapply tree_equal_trans. 8-9: eassumption. - 2: by eapply Hu2. 1: by eapply Hu1. 1: by eapply Hu3. 1: by eapply Hu4. 1: by eapply Hu5. 1: by eapply Hu6. 1: by eapply Hu7. - Qed. - -End utils. - -Section call_set. - - Lemma call_is_active_mono C1 C2 cid : - C1 ⊆ C2 → - call_is_active cid C1 → - call_is_active cid C2. - Proof. - rewrite /call_is_active. set_solver. - Qed. - - Lemma protector_is_active_mono C1 C2 prot : - C1 ⊆ C2 → - protector_is_active prot C1 → - protector_is_active prot C2. - Proof. - intros Hss (c&Hc1&Hc2). eexists; split; by eauto using call_is_active_mono. - Qed. - - Lemma pseudo_conflicted_mono C1 C2 tr tg off rc : - C1 ⊆ C2 → - pseudo_conflicted C1 tr tg off rc → - pseudo_conflicted C2 tr tg off rc. - Proof. - induction 2. - + econstructor 1. - + econstructor 2; by eauto using protector_is_active_mono. - Qed. - - Lemma protector_not_active_extend - {p c C} - (Hwf : ∀ c' : nat, protector_is_for_call c' p → (c' < c)%nat) - (NoProt : ¬ protector_is_active p C) - : ¬ protector_is_active p (C ∪ {[ c ]}). - Proof. - intros (cc&Hcc&[Hact|<-%elem_of_singleton]%elem_of_union). - 1: eapply NoProt; by eexists. - apply Hwf in Hcc. lia. - Qed. - - Lemma pseudo_disabled_mono C1 nxtc tr1 tg l p1 cid : - pseudo_disabled C1 tr1 tg l p1 cid → - pseudo_disabled (C1 ∪ {[ nxtc ]}) tr1 tg l p1 cid. - Proof. - induction 1 as [|???????? HH]. 1: by econstructor 1. - econstructor 2. 1,2,4: done. - 1: eapply protector_is_active_mono; last done; set_solver. - done. - Qed. - - Lemma is_disabled_mono C1 nxtc tr1 tg l p1 cid : - is_disabled C1 tr1 tg l p1 cid → - is_disabled (C1 ∪ {[ nxtc ]}) tr1 tg l p1 cid. - Proof. - induction 1 as [|]. 1: by econstructor 1. - econstructor 2. eapply pseudo_disabled_mono. done. - Qed. - - Lemma disabled_in_practice_mono C1 nxtc tr1 tg tg2 l: - disabled_in_practice C1 tr1 tg tg2 l → - disabled_in_practice (C1 ∪ {[ nxtc ]}) tr1 tg tg2 l. - Proof. - induction 1. econstructor. 1-2: done. - eapply is_disabled_mono. done. - Qed. - - Lemma perm_eq_up_to_C_mono (C1 : gset nat) (nxtc : nat) - tr1 tr2 tg l cid lp1 lp2 {d nxtp} : - (∀ cc, protector_is_for_call cc cid → (cc < nxtc)%nat) → - tree_items_compat_nexts tr1 nxtp nxtc → - tree_items_compat_nexts tr2 nxtp nxtc → - wf_tree tr1 → - wf_tree tr2 → - perm_eq_up_to_C C1 tr1 tr2 tg l cid d lp1 lp2 → - perm_eq_up_to_C (C1 ∪ {[ nxtc ]}) tr1 tr2 tg l cid d lp1 lp2. - Proof. - intros Hwf Hwf_all1 Hwf_all2 Hwf_tr1 Hwf_tr2. - induction 1 as [| |??? H|?? H1 H2|??? H1 H2 ?| |p1 p2 ini Hd]. - 1: by econstructor. - 1: econstructor; try done. 1: eapply protector_is_active_mono; last done; set_solver. - 1-2: eapply pseudo_conflicted_mono; last done; set_solver. - - econstructor 3; try done. - apply protector_not_active_extend; assumption. - - econstructor 4. all: eapply pseudo_disabled_mono; last done; done. - - econstructor 5; try done. - all: eapply disabled_in_practice_mono; last done. - - econstructor 6; done. - - econstructor 7. destruct d; inversion Hd as [x1 Hp|]; simplify_eq. - all: econstructor. - 2,4: eapply protector_is_active_mono; last done; set_solver. - all: eapply protector_not_active_extend; done. - Qed. - - Lemma loc_eq_up_to_C_mono C1 d tr1 tr2 tg it1 it2 nxtc nxtp l : - item_wf it1 nxtp nxtc → - tree_items_compat_nexts tr1 nxtp nxtc → - tree_items_compat_nexts tr2 nxtp nxtc → - wf_tree tr1 → - wf_tree tr2 → - loc_eq_up_to_C C1 tr1 tr2 tg d it1 it2 l → - loc_eq_up_to_C (C1 ∪ {[ nxtc ]}) tr1 tr2 tg d it1 it2 l. - Proof. - intros Hwf1 Hwf_all1 Hwf_all2 Hwf_tr1 Hwf_tr2. - induction 1; econstructor; try done. - eapply perm_eq_up_to_C_mono; last done. - 1: apply Hwf1. - all: eassumption. - Qed. - - Lemma item_eq_up_to_C_mono C1 d tr1 tr2 tg it1 it2 nxtc nxtp : - item_wf it1 nxtp nxtc → - tree_items_compat_nexts tr1 nxtp nxtc → - tree_items_compat_nexts tr2 nxtp nxtc → - wf_tree tr1 → - wf_tree tr2 → - item_eq_up_to_C C1 tr1 tr2 tg d it1 it2 → - item_eq_up_to_C (C1 ∪ {[ nxtc ]}) tr1 tr2 tg d it1 it2. - Proof. - intros Hss Hwf_all1 Hwf_all2 Hwf_tr1 Hwf_tr2 H1 l. - specialize (H1 l). by eapply loc_eq_up_to_C_mono. - Qed. - - Lemma tree_equal_mono C1 d tr1 tr2 nxtc nxtp : - tree_items_compat_nexts tr1 nxtp nxtc → - tree_items_compat_nexts tr2 nxtp nxtc → - wf_tree tr1 → - wf_tree tr2 → - tree_equal C1 d tr1 tr2 → - tree_equal (C1 ∪ {[ nxtc ]}) d tr1 tr2. - Proof. - intros Hss Hss2 Hwf_tr1 Hwf_tr2 (H1&H2&H3). do 2 (split; first done). - intros tg (it1&it2&H4&H5&H6)%H3. - exists it1, it2. split_and!; try done. - eapply item_eq_up_to_C_mono; try done. - setoid_rewrite every_node_eqv_universal in Hss. - apply Hss. eapply tree_lookup_to_exists_node. - erewrite <-tree_lookup_correct_tag in H4; done. - Qed. - - Lemma trees_equal_mono C1 d trs1 trs2 nxtc nxtp : - trees_compat_nexts trs1 nxtp nxtc → - trees_compat_nexts trs2 nxtp nxtc → - wf_trees trs1 → - wf_trees trs2 -> - trees_equal C1 d trs1 trs2 → - trees_equal (C1 ∪ {[ nxtc ]}) d trs1 trs2. - Proof. - intros Hss Hss2 Hwf_trs1 Hwf_trs2 Heq blk. specialize (Heq blk). inversion Heq; simplify_eq. - all: econstructor; try done. - eapply tree_equal_mono; try done. - + eapply Hss. done. - + eapply Hss2. done. - + eapply Hwf_trs1. done. - + eapply Hwf_trs2. done. - Qed. - -End call_set. - -