rocq/theories/Identity.v
Objects last: what a run of Machine R, the machine over a runtime R, leaves of the objects it finds (docs/formal.md, Campaign 3; docs/rocq.md, Identities persist).
The reuse forms trust a check that passed earlier, as long as the names it read are unchanged. That is sound only if the object it checked is still there when the reuse comes: as it was, so the check passes again, or freed, so it traps out of bounds. A run must never lose the object, or a new one could take its base and an old capability would name the new object. This file proves that memory persists over every run that starts ready (mreachable_persists): every object keeps its identity.
Decisions
| Decision | Why |
|---|---|
free_ids follows from an axiom | the module type's free_lifetime says each identity after a free was one before, not the reverse; free_keeps_ids (mbrock's decision, with axiom-identity.c) says the reverse, as rooting does at safepoints |
| an allocation's base was no object's | fresh says so, which is what keeps an old capability from naming the new object |
| the regions of a step are compared, not its bytes | kept already says where a step writes; identity is about the region list alone |
Identities persist
Every object of memory m is still an object of memory m': each base that names a region in m (object_region) names one in m', possibly changed. A step that satisfies this keeps every identity.
The region reg as a free, or the end of its frame, leaves it: the same base and kind, its bounds emptied (its end at its base), and marked Freed, so that every access to it traps out of bounds.
Each object of memory m is in memory m' as it was, or as its freed_region: nothing is lost, and no base is given to another object. This is how memory persists along a run, and why a check that passed in m passes again in m' or traps (persists_access).
The region object_region finds for base b in a region list rs has base b.
Explore proof 3 tactics
Initial goal
intros b rs reg
induction rs as | r rs IH ; simpl ; discriminate |
destruct Z.eqbr_baser b eqn: E ; intros H ; injection H as ← ; apply Z.eqb_eq ; exact E | exact IH
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A memory persists from itself.
Explore proof 3 tactics
Initial goal
intros m b reg H
left
exact H
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Persistence composes: if m2 persists from m1 and m3 from m2, then m3 persists from m1.
Explore proof 5 tactics
Initial goal
intros m1 m2 m3 H12 H23 b reg H1
destruct H12_ _ H1 as H2 | H2
2 openfocused goal
–exact H23_ _ H2
deferred goal
–right
destruct H23_ _ H2 as H3 | H3 ; exact H3
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A memory m' with the same region list as m persists from m.
Explore proof 4 tactics
Initial goal
intros m m′ E b reg H
left
rewrite E
exact H
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A change of memory from m to m' persists where it is a region_step (each object of m' was one of m, unchanged or ended in place) and loses no identity (ids). These are what the program and the runtime may do to regions.
Explore proof 10 tactics
Initial goal
intros m m′ Hr Hi b reg H
destruct Hi_ _ H as reg′ H′
destruct Hr_ _ H′ as reg0 & E0 & → | _ & → ; rewrite H in E0 ; injection E0 as ←
2 openfocused goal
–left
2 opendeferred goal
exact H′
deferred goal
–right
rewrite H′
unfold freed_region
rewrite object_region_base_ _ _ H
reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
The same for a lifetime_step, what the runtime's free and its safepoint action may do: with no identity lost, memory persists.
Explore proof 2 tactics
Initial goal
intros m m′ Hl Hi
exact region_ids_persists_ _ lifetime_region_step_ _ Hl Hi
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
The same for kept, what the program's own steps between allocations may do to memory.
Explore proof 2 tactics
Initial goal
intros m m′ Hr _ Hi
exact region_ids_persists_ _ Hr Hi
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Explore proof 8 tactics
Initial goal
intros m q base Hn b reg H
left
simpl
destruct Z.eqbbase b eqn: E ; | exact H
apply Z.eqb_eq in E
subst
rewrite Hn in H
discriminate H
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Steps that write keep the regions
A store (store_res, store_res/7) writes bytes but leaves the region list unchanged.
Explore proof 3 tactics
Initial goal
unfold store_res
intros w m a c x r m′ H
destruct w , x ; try discriminate ; cases H ; inversion H ; reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Folding a memory update f over a list xs leaves the region list unchanged where each application of f does. A helper for lists of store effects.
Explore proof 9 tactics
Initial goal
intros A f xs
induction xs as | x xs IH ; simpl ; intros m0 m′ Hf H
2 openfocused goal
–injection H as ←
2 opendeferred goal
reflexivity
deferred goal
–destruct fm0 x as m1 | eqn: E
2 openfocused goal
+rewrite IH_ _ Hf H
2 opendeferred goal
exact Hf_ _ _ E
deferred goal
+rewrite fold_left_none in H
discriminate H
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
The effects of storing the pointer x at address a (pointer_store_effects, pointer_store_effects//6) leave the region list unchanged.
Explore proof 4 tactics
Initial goal
intros a x m es m′ H
apply fold_regionseffect pointer_store_effecta x es m m′ ; | exact H
intros m1 e m2 E
destruct e ; simpl in E ; try discriminate E ; injection E as ← ; reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Reading a variadic argument through the argument pointer p (va_arg_res) leaves the region list unchanged, though it may write memory.
Explore proof 3 tactics
Initial goal
unfold va_arg_res
intros k p m r m′ H
cases H;match type of H withSome_, = Some_, ⇒assert x = y as ← by congruenceend;first
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Explore proof 3 tactics
Initial goal
unfold op_res , float_integer
intros o k xs m r m′ H
destruct o ; cases H ; inversion H ; subst;first
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A memory keeps its own identities.
Explore proof 2 tactics
Initial goal
intros m b reg H
eauto
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Keeping identities composes, from m1 to m2 to m3.
Explore proof 3 tactics
Initial goal
intros m1 m2 m3 H12 H23 b reg H
destruct H12_ _ H as reg2 H2
exact H23_ _ H2
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A memory with the same region list as m keeps every identity of m.
Explore proof 3 tactics
Initial goal
intros m m′ E b reg H
rewrite E
eauto
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Ending an invocation's named locals as it returns, as invalidate_locals/3 does, frees each in place and drops no object: every identity is kept.
Explore proof 14 tactics
Initial goal
unfold invalidate_locals
intros locals
induction locals as | x slot ls IH ; simpl ; intros m m′ H
2 open–injection H as ←
2 openapply ids_refl
–destruct slot as base | ; | exact IH_ _ H
destruct object_regionbase m_regionsm as reg | eqn: Er ; simpl in H ; | rewrite fold_left_none in H ; discriminate H
destruct r_kindreg , r_lifereg ; simpl in H ; try rewrite fold_left_none in H ; discriminate H
destruct replace_regionbase _ m_regionsm as rs | eqn: Ers ; simpl in H ; | rewrite fold_left_none in H ; discriminate H
eapply ids_trans ; | exact IH_ _ H
intros b r0 Hb
simpl
rewrite object_region_replace_ _ _ _ b Ers eq_refl
destruct Z.eqbb base ; eauto
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A step keeps every identity
A free function (from a pointer word and a memory to a result and a new memory) keeps every identity: what it frees stays an object, freed in place. The runtime axiom free_keeps_ids gives this of R's free (R_free_ids).
Explore proof 4 tactics
Initial goal
intros ge fr m i e l m′ Hfree H
destruct i
8 openfocused goal
focused goal
focused goal
focused goal
focused goal
focused goal
1: destruct special_leto eqn: Es ; destruct o ; try discriminate Es | rewrite inst_step_let_ _ _ _ _ _ _ Es in H
11 openfocused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
all: unfold inst_step , external_call , bind_res , store_out in H ; cases H ; inversion H ; subst;first
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A return (return_step) from configuration c to c' keeps every identity: it only ends the returning frame's locals.
Explore proof 5 tactics
Initial goal
unfold return_step
intros c o c′ H
apply or_stuck_next in H
cases H ; inversion H ; subst ; simpl
match goal withE : invalidate_locals_ _ = Some_ |- _⇒exact invalidate_locals_ids_ _ _ Eend
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A jump at the end of block l (jump_step) keeps every identity: it takes an edge, which leaves memory alone, or returns.
Explore proof 4 tactics
Initial goal
unfold jump_step , edge_step
intros ge c l j c′ H
cases H ; unstuck H
9 openfocused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
all: first
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
A step of configuration c that allocates nothing (Next c') keeps every identity of its memory, where ge's free does. Allocations are step_fresh_regions.
Explore proof 4 tactics
Initial goal
unfold step , inst_next
intros ge c c′ Hfree H
cases H ; unstuck H
5 openfocused goal
focused goal
focused goal
focused goal
all: first
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Storing the variadic arguments xs from address a (snapshot_values, snapshot_values/5), as a variadic function's entry does into its new snapshot object, leaves the region list unchanged.
Explore proof 2 tactics
Initial goal
induction xs as | x xs IH ; intros a m ; simpl ; reflexivity |
destruct x ; rewrite IH ; reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Proof 5 steps Qed
Explore proof 5 tactics
Initial goal
intros ge fr m i q k H
destruct i
8 openfocused goal
focused goal
focused goal
focused goal
focused goal
focused goal
1: destruct special_leto eqn: Es ; destruct o ; try discriminate Es | rewrite inst_step_let_ _ _ _ _ _ _ Es in H
11 openfocused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
all: unfold inst_step , external_call , bind_res , store_out in H ; cases H ; inversion H ; subst ; intros base
2 openfocused goal
all: first
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A step that allocates (Fresh q k) does the same: whatever base the runtime gives, the next configuration's regions are the old ones with the new object added. An allocation adds one identity and drops none.
Explore proof 11 tactics
Initial goal
unfold step , inst_next
intros ge c q k H
cases H ; unstuck H ; try exfalso ; exact jump_step_not_fresh_ _ _ _ _ _ H
2 openall: injection H as Hq Hk ; subst q k ; intros base
2 open–match goal withHp : fr_at_ = Snapshot _ |- _⇒exact snapshot_values_regionsxs base _end
–match goal withE : doomed_result_ _ _ _ _ = Some , Hc : fst = IFresh_ _ |- _⇒destruct doomed_result_out_ _ _ _ _ _ E as Ho | e′ & l′ & Ho | o′ & Ho ; rewrite Ho in Hc ; try discriminate Hcend
subst
match goal withE2 : inst_step_ _ _ _ = SomeIFresh_ |- _⇒pose proof inst_step_fresh_regions_ _ _ _ _ _ E2 base as Hkend
simpl
match goal withHk : m_regionssnd = _ |- _⇒destruct t as e1 l1 m1end
exact Hk
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A check that passed passes again, or its object was freed
Where an access check of a nonempty range (size bytes at address a, through the capability c, with rights r and alignment al) passed in memory m, it passes the same way in any memory m' that persists from m, or traps out of bounds because the object was freed. This is what makes it sound to reuse a check.
Explore proof 3 tactics
Initial goal
unfold access_res , cap_access_res
intros m m′ a c size r al u Hp Hs H
destruct c as | base | base | f | n ; try discriminate H ; destruct object_regionbase m_regionsm as reg | eqn: E ; try discriminate H ; destruct Hp_ _ E as E′ | E′ ; rewrite E' ; left ; exact H | right | left ; exact H | right ; pose proof object_region_base_ _ _ E as Hb ; simpl ; rewrite Hb ; destruct base ≤? a && a + size ≤? base eqn: Eb ; try reflexivity ; apply andb_true_iff in Eb as E1 E2 ; apply Z.leb_le in E1 ; apply Z.leb_le in E2 ; lia
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Over runs
R's free keeps every identity, by the runtime axiom free_keeps_ids: free reclaims nothing; only the collector does, at a safepoint.
Explore proof 5 tactics
Initial goal
intros x m r m′ H b reg Hb
pose proof R.free_keeps_ids_ _ _ _ H b as Hk
destruct object_regionb m_regionsm′ as reg′ | ; eauto |
exfalso
apply Hk ; rewrite Hb ; discriminate | reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Each machine step (mstep) from a state where R is ready (ready_state) persists memory, where the genv's free is R's: a step that allocates nothing ends objects in place, an allocation adds one at a fresh base, and R's safepoint action keeps every identity (rooting).
Explore proof 17 tactics
Initial goal
unfold ready_state
intros ge st st′ Hge Hr Hs
destruct Hs as c c′ s E | c q k s base s′ E He Hal | c s s′ m′ _ Hsp ; simpl in *
3 openfocused goal
–apply kept_ids_persists
4 openfocused goal
deferred goal
+eapply step_next_kept ; rewrite Hge ; exact free_kept | exact E
3 opendeferred goal
deferred goal
+eapply step_next_ids ; rewrite Hge ; exact R_free_ids | exact E
2 opendeferred goal
–destruct step_fresh_kept_ _ _ _ E as Ha _
2 opendestruct R.fresh_allocation_ _ _ _ _ Hr Ha He Hal as _ & _ & _ & Hnone & _ _
2 openeapply persists_trans ; exact allocated_persists_ q _ Hnone |
2 openapply persists_same
2 openexact step_fresh_regions_ _ _ _ E base
–apply lifetime_ids_persists ; exact R.safepoint_lifetime_ _ _ _ Hsp |
intros b reg H
pose proof R.rooting_ _ _ _ Hsp b as Hroot
destruct object_regionb m_regionsm′ as reg′ | eqn: E′ ; eauto |
exfalso
apply Hroot ; rewrite H ; discriminate | reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Over a run that starts ready, the memory of every later state (mreachable: any number of machine steps) persists from the first: each object is in every later state as it was, or freed.
Explore proof 5 tactics
Initial goal
intros ge st st′ Hge H
induction H as st st′ Hs | st | st1 st2 st3 H12 IH1 _ IH2 ; intros Hr
3 openfocused goal
–eapply mstep_persists ; eauto
2 opendeferred goal
–apply persists_refl
–eapply persists_trans ; exact IH1Hr | apply IH2 ; exact mreachable_ready_ _ _ Hge H12 Hr
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
The same for the interpreter's runtime InterpRuntime, which proves every runtime axiom.
Under the interpreter's runtime, every run that starts ready persists memory, with no hypothesis but that the genv's free is the interpreter's.
Explore proof 2 tactics
Initial goal
intros ge st st′ Hge H Hr
exact InterpIdentity.mreachable_persists_ _ _ Hge H Hr
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.