rocq/theories/ContractFrame.v
The program logic's frame for external calls (Logic.v, docs/logic.md): what a call through a contract leaves of the ghost heap of Heap.v.
A call changes memory along an effects path of Campaign 4 (ExternalCalls.v): local_effect segments, which write bytes and aux slots only where the call has write_authority and change an object only by freeing a live heap object it may release or allocated itself, and allocations at a fresh base, which join the call's born objects. The program logic owns pieces of memory (agrees with a ghost heap h), and asks what of them survives the call.
The premise is separation by address, not by identity: no address of a contract's writable roots lies in a live object that owns a piece of h (roots_apart), and the contract releases none of h's identities (ids_apart). Then the call's born objects are not the program's, it writes nothing the program owns, and after the whole path h still agrees with memory and live objects are still apart (Logic.v's effects_agrees, prefix_agrees and invoke_agrees, over the language's own call relations). A world's new roots that a call delegates from its old roots and born objects stay apart as well (delegates_apart).
A call may also write blocks the program hands it, such as mbrtowc's output, state and errno cells. Then its roots touch the program's objects only at the addresses of those blocks (roots_out), and every piece but the handed-over ones keeps agreeing (agrees_except, local_agrees_out; Logic.v's effects_agrees_out and prefix_agrees_out).
Byte and aux pieces of an object that is not live need only stay registered, and an aux piece of a live one is known up to aux_holds; regions of old identities change only by being freed, so a freed capability stays freed and one that traps as freed keeps trapping (freed_in_step, traps_as_freed_step). Released or not, no piece but a life token needs its object kept live; a life token does, which is what ids_apart of the releases gives.
Separation of a call from the program's pieces
The address a lies in a live object of m that owns a piece of memory in the ghost heap h.
No address of the spans roots lies in a live object owning a piece of h.
None of the identities bs is that of a piece of memory in h.
A call whose roots are apart from h and whose born objects are none of h's has no write_authority over an address of a live object owning a piece of h: a born live heap object overlapping it would be another live object over the same address.
Explore proof 5 tactics
Initial goal
intros roots born h m a Hd Hr Hb Ho s & Hin & _ & Hs | base & reg & Hin & E & _ & L & Ha
2 openfocused goal
–exact Hrs a Hin Hs Ho
deferred goal
–destruct Ho as l & v & reg0 & Hl & Hm & Hlive & Ha0
specialize Hbbase l v Hin Hl Hm
destruct Hdpiece_idl reg0 base reg Hlive conjE L Hb ; lia
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Steps that keep old identities
A freed object's capability stays freed across a step that keeps every identity (ids) and changes an object only by ending a live one (region_step).
Explore proof 6 tactics
Initial goal
intros m m′ c Hi Hs b & reg & Hc & E & L
destruct Hib reg E as reg′ E′
destruct Hsb reg′ E′ as reg0 & E0 & → | L0 & _ ; rewrite E in E0 ; injection E0 as ←
2 open–exists b, reg
2 openauto
–congruence
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A capability that traps as a freed one keeps doing so across such a step: its object's region is kept, or emptied.
Explore proof 10 tactics
Initial goal
intros m m′ c Hi Hs H a size r align Hsz
specialize Ha size r align Hsz
assert Hempty : ∀b, b ≤? a && a + size ≤? b = false
2 openfocused goal
{intros b
2 opendeferred goal
destruct Z.leb_specb a ; cbn [ andb ] ; apply Z.leb_gt ; lia | reflexivity
deferred goal
assert Hreg : ∀b reg, object_regionb m_regionsm = Somereg → object_regionb m_regionsm′ = Somereg ∨ object_regionb m_regionsm′ = SomemkRegionb b r_kindreg Freed
2 openfocused goal
{intros b reg E
2 opendeferred goal
destruct Hib reg E as reg′ E′
2 opendeferred goal
destruct Hsb reg′ E′ as reg0 & E0 & → | _ & → ; rewrite E in E0 ; injection E0 as ← ; auto
deferred goal
destruct c as | b | b | f | n ; cbn [ cap_access_res ] in H |- * ; try exact H ; destruct object_regionb m_regionsm as reg | eqn: E ; | discriminate H ; destruct Hregb reg E as E′ | E′ ; rewrite E' ; exact H | ; cbn [ r_end ] ; rewrite Hempty ; reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A call into owned blocks
Every piece of h but the keys ks agrees with m: a ghost heap whose pieces ks a call may overwrite.
Every address of the spans roots that lies in a live object owning a piece of h is one of the addresses out, which the program hands to the call.
No byte or aux piece of h but the keys ks, of a live object of m and in its bounds, lies at an address out.
With nothing out, roots that avoid h's live objects.
Explore proof 2 tactics
Initial goal
intros Hra s a Hin Hs Ho
exact Hras a Hin Hs Ho
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A local effect
One local_effect of a call, from m to m', against the ghost heap h.
The call's sources, roots, releases and born objects, the memories before and after, and the ghost heap.
The step is a local_effect.
A live object of m' was live in m with the same region: a local effect only ends objects.
Explore proof 3 tactics
Initial goal
intros b reg E L
destruct Hl as _ & Hr & _
destruct Hrb reg E as reg0 & E0 & → | _ & _ & _ & → ; split ; assumption | discriminate L
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A local effect keeps live objects apart.
Explore proof 2 tactics
Initial goal
intros Hd b1 r1 b2 r2 H1 H2
exact Hdb1 r1 b2 r2 local_live_back_ _ H1 local_live_back_ _ H2
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
An address of a live owned object of m' was one of m.
Explore proof 5 tactics
Initial goal
intros a l & v & reg & Hh & Hm & Hlive & Ha
exists l, v, reg
split ; exact Hh |
split ; exact Hm |
split ; exact local_live_back_ _ Hlive | exact Ha
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A local effect keeps every piece of h but the keys ks agreeing, where every root address in an object the program owns is out, no piece of h but ks lies at an address out, and the effect releases none of h's identities and was born with none of them. The program hands the call the pieces ks, at the addresses out.
Proof 55 steps Qed
An address of a live object of m owning a piece of h, not out, keeps its byte and aux slot.
A local effect whose roots are apart from h, that releases none of h's identities and was born with none of them, keeps h agreeing.
Explore proof 6 tactics
Initial goal
intros Hd Ha Hra Hrel Hb l v Hh
apply local_agrees_out[ ] λ_ ⇒ False Hd ; | exact roots_out_apart_ _ _ Hra | | exact Hrel | exact Hb | exact Hh | apply not_elem_of_nil
2 openfocused goal
–intros l′ v′ Hl′ _
2 opendeferred goal
exact Hal′ v′ Hl′
deferred goal
–intros l′ v′ _ _
destruct l′ ; auto
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
An allocation
A live object of m after an allocation at a new base, other than the new object, was live in m with the same region.
Explore proof 3 tactics
Initial goal
intros m q base b reg Hne E L
rewrite object_region_allocated in E
destruct Z.eqb_specbase b as [ <-| _ ] ; contradiction | split ; assumption
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
An address of a live owned object after an allocation at a base that is no object of m was one of m: owned objects are registered.
Explore proof 10 tactics
Initial goal
intros m q base h a Hn Ha l & v & reg & Hh & Hm & Hlive & Hr
exists l, v, reg
split ; exact Hh |
split ; exact Hm |
split ; | exact Hr
apply allocated_live_backm q base ; | exact Hlive
intros E
apply agree_piece_registeredm l v Hm Hal v Hh
rewrite <- E
exact Hn
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A base that is no object of m is none of the identities of a ghost heap that agrees with m.
Explore proof 6 tactics
Initial goal
intros m h base bs Hn Ha Hb b l v [ <-| Hin ] Hh Hm
2 open–intros E
2 openapply agree_piece_registeredm l v Hm Hal v Hh
2 openrewrite E
2 openexact Hn
–exact Hbb l v Hin Hh Hm
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Delegated roots
A world's new roots, delegated in m from the old roots and the born objects (stdio_delegates), avoid h's live objects when the old roots do and the born objects are none of h's: every address of a new root is one the call has write_authority over.
Explore proof 3 tactics
Initial goal
intros roots born m w h Hdel Hra Hb Hd s a Hin Hs Ho
destruct Hdels Hin as _ Hw
exact owned_not_authorityroots born h m a Hd Hra Hb Ho Hwa Hs
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.