rocq/spikes/IrisListSum.v
Spike: spikes/listsum.c proved never to panic through Iris, with the ghost heap and rules of IrisHeap.v, the same theorem the hand-rolled spike proves.
A node is the life of its 16-byte heap object, the aux slot of its next pointer and the 16 bytes of the next pointer's address and its value (node_ps); a list is a Fixpoint over the values (lst). sum gets one specification (sum_spec): from lst p xs, a call with any caller frame and callers stack is safe if the caller, resumed with any result and any fuel, is; that continuation is a resource the callee carries to its return (the rule for a call that the language, having no evaluation contexts, does not give). Each loop is a Löb induction at the point after its head's phis. Each step is computed as Symbolic.v computes one, without splitting a comparison and without generalising a wrap, so that the next configuration is a term the rule's existential frame can take.
Integer arithmetic on an unknown stays folded when a step is computed (Symbolic.v).
The blocks, computed once
Block l of the function f, or an empty one.
sum's entry block.
sum's loop head.
sum's loop body.
sum's exit.
listsum's entry block.
listsum's loop head.
listsum's loop body.
listsum's exit, the call of sum.
sum has its entry block.
Explore proof 2 tactics
Initial goal
vm_compute
reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
sum has its loop head.
Explore proof 2 tactics
Initial goal
vm_compute
reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
sum has its loop body.
Explore proof 2 tactics
Initial goal
vm_compute
reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
sum has its exit.
Explore proof 2 tactics
Initial goal
vm_compute
reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
listsum has its entry block.
Explore proof 2 tactics
Initial goal
vm_compute
reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
listsum has its loop head.
Explore proof 2 tactics
Initial goal
vm_compute
reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
listsum has its loop body.
Explore proof 2 tactics
Initial goal
vm_compute
reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
listsum has its exit.
Explore proof 2 tactics
Initial goal
vm_compute
reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
sum returns a long.
Explore proof 2 tactics
listsum returns a long.
Explore proof 2 tactics
Computing a step
Drop the wraps in E that arithmetic over the context proves are the identity, innermost first; leave every other wrap as it is.
Decide the integer comparisons in E that arithmetic over the context decides; leave every other one as it is.
Rewrite in E what the context knows of memory (a load or an aux slot at an address arithmetic identifies), the module's function sum and its call frame.
Reduce E, an equation r = step g c, as far as the facts and arithmetic allow, keeping the module, its functions, memory operations and calls folded.
Replace each environment put k v e of the goal, e a variable, by a new variable, with what each name looks up to in it.
Over any runtime
The genv of the module, whose free is R's.
Put the facts about the module's blocks, return classes, sum and its call frame in the context.
Prove a goal step g c = r', with r' possibly holding existential variables, by computing the step.
A one-instruction step that changes no memory.
Entering a block: when the fuel F is 0 the run ends with OutOfFuel; otherwise the goal is left with F not 0.
The pieces of a node at b: its life as a 16-byte heap object, the aux slot holding the next pointer nx's capability, the bytes of nx's address, and the bytes of the value x.
The list from p holds the values xs: null for none; otherwise p is its object's own pointer, at a positive, 16-aligned base that fits the address space, and the node there points to the rest.
The head of a list is null or a live object.
Explore proof 18 tactics
Initial goal
destruct xs as | x xs ; cbn [ lst ]
2 openfocused goal
–iIntros _ ->
2 opendeferred goal
iPureIntro
2 opendeferred goal
left
2 opendeferred goal
split ; reflexivity
deferred goal
–iIntros Hσ Hl
iDestruct Hl as b nx → & Hb0 & Hb1 & _ [Hn _]
iDestruct pts_facts with Hσ Hn as %Hf & _
iPureIntro
right
exists b
split ; reflexivity |
split ; exact Hb0 |
split ; exact Hb1 |
unfold node_ps in Hf
apply all_agree_app in Hf as Hf _
cbn [ all_agree fst snd agree_piece ] in Hf
exact proj1Hf
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
What a node at b and the list after it tell a step: b's region, the value's and the next address's bytes, and the next pointer's capability in the aux slot, exactly, since its object is live.
Explore proof 28 tactics
Initial goal
iIntros Hσ Hn Hl
iDestruct pts_facts with Hσ Hn as %Hf & _
iDestruct lst_head with Hσ Hl as %Hh
iPureIntro
unfold node_ps in Hf
apply all_agree_app in Hf as Hla Hf
apply all_agree_app in Hf as Hax Hf
apply all_agree_app in Hf as Hc0 Hc8
cbn [ all_agree fst snd agree_piece ] in Hla , Hax
destruct Hla as Hlive _
destruct Hax as _ & Hax _
pose proof Hlive as E L
split ; exact E |
split ; | split
3 openfocused goal
focused goal
–intros a →
3 opendeferred goal
deferred goal
exact cell_loadm b _ 8 x b + 8 Hlive Hc8 eq_refl
2 opendeferred goal
deferred goal
–intros a →
2 opendeferred goal
rewrite cell_loadm b _ 0 ptr_addrnx b Hlive Hc0 ; | lia
2 opendeferred goal
apply Z.mod_small
2 opendeferred goal
destruct Hh as _ → | nb & → & ? & ? & _ ; cbn ; lia
deferred goal
–intros a →
destruct Hax_ E L as _ & _ & Hx
replace b + 0 with b in Hx by lia
apply aux_holds_live ; exact Hx |
destruct Hh as → _ | nb & → & _ & _ & Hl ; left ; reflexivity |
right
exists nb, mkRegionnb nb + 16 Heap Live
split ; reflexivity | exact Hl
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A step of sum's loop body that may read the node at b.
The continuation of a call of sum from the caller frame cf, whose result is bound to d: cf resumed with any result and any fuel.
sum's loop, from the point after its head's phis: with pr.1 the list's pointer p and pr.2 an integer, owning the list and the continuation, the run is safe. By Löb induction.
Explore proof 26 tactics
Initial goal
iLöb as IH
iIntros e p xs fuel Hp s0 Hs Hl HK
destruct xs as | x xs
2 openfocused goal
–iDestruct Hl as %→
2 opendeferred goal
wp_emp
2 opendeferred goal
wp_emp
2 opendeferred goal
wp_emp
2 opendeferred goal
wp_fuel
2 opendeferred goal
wp_emp
2 opendeferred goal
iApply wpc_next_ emp%I with [//] ; let m ≔ fresh "m" in let s ≔ fresh "s" in iIntros m s _ _ ; iPureIntro ; compute_eq | iNext ; iIntros _ ; iApply HK
deferred goal
–iDestruct Hl as b na nc → & Hb0 & Hb1 & Hb2 [Hn Hl]
wp_node b mkPtrna nc x xs
wp_node b mkPtrna nc x xs
wp_node b mkPtrna nc x xs
wp_fuel
wp_node b mkPtrna nc x xs
wp_node b mkPtrna nc x xs
wp_node b mkPtrna nc x xs
wp_node b mkPtrna nc x xs
wp_node b mkPtrna nc x xs
wp_node b mkPtrna nc x xs
wp_node b mkPtrna nc x xs
wp_node b mkPtrna nc x xs
wp_fuel
wp_node b mkPtrna nc x xs
iApply IH $! _ mkPtrna nc xs with [%] [%] Hl HK ; eassumption | eexists ; eassumption
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
sum's specification, the rule for calling it: from any caller frame cf whose call binds the result to d, over any callers stack, owning the list from p and the continuation, the call is safe.
Explore proof 7 tactics
Initial goal
iIntros Hl HK
wp_fuel
wp_emp
wp_emp
wp_fuel
wp_emp
iApply sum_loop with [%] [%] Hl HK ; reflexivity | eexists ; reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
A new node's object, split into the pieces the loop body uses: its life, its first aux slot, and its two cells; the other aux slots are dropped.
Explore proof 4 tactics
Initial goal
assert E : obj_psbase heap_req16 16 = PLivebase, VLivemkRegionbase base + 16 Heap Live ++ cellbase 0 0 ++ cellbase 8 0 ++ PAuxbase 0, VAuxCNone ++ λi ⇒ PAuxbase i, VAuxCNone <$> seqZ1 15 by reflexivity
rewrite E ! pts_app
iIntros (Hl & H0 & H8 & Ha & _)
iFrame
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
A step of listsum's loop body that may read the new object's region.
listsum's loop, from the point after its head's phis: with pr.2 an int i in range, pr.1 the list's pointer h and v0 the input, owning the list, the run is safe. By Löb induction; each iteration allocates a node, stores h and i in it, and the loop goes on with i + 1 and the longer list; at the end sum is called with the list.
Explore proof 48 tactics
Initial goal
iLöb as IH
iIntros e i h xs fuel Hi & Hir & Hh & Hn Hl
wp_emp
match goal withH : lookupTAtom"v10" _ = SomeWIntif then 1 else 0 |- _⇒destruct c eqn: Hcend
2 openfocused goal
–assert Hi1 : i + 1 < 2 ^ 31
3 openfocused goal
deferred goal
{apply Z.ltb_lt in Hc
3 opendeferred goal
deferred goal
revert Hc
3 opendeferred goal
deferred goal
repeat match goal with|- context [if then _ else _]⇒let Hb ≔ fresh in destruct b eqn: Hb ; apply Z.leb_le in Hb | apply Z.leb_gt in Hbend;intros;pose proof Z.mod_pos_boundn 2 ^ 32 ltac:lia;pose proof Z.mod_pos_boundn mod 2 ^ 32 2 ^ 32 ltac:lia;lia
2 opendeferred goal
deferred goal
wp_emp
2 opendeferred goal
wp_fuel
2 opendeferred goal
wp_emp
2 opendeferred goal
iApply wpc_alloc_ heap_req16 16 ; vm_compute ; reflexivity | vm_compute ; discriminate | let m ≔ fresh "m" in intros m ; compute_eq |
2 opendeferred goal
iNext
2 opendeferred goal
iIntros base Hb0 & Hb1 & Hb2 Hobj
2 opendeferred goal
cbv beta
2 opendeferred goal
change req_alignheap_req16 16 with 16 in Hb1
2 opendeferred goal
change req_extentheap_req16 16 with 16 in Hb2
2 opendeferred goal
iDestruct obj_split with Hobj as (Hlv & Hax & Hc0 & Hc8)
2 opendeferred goal
gen_env
2 opendeferred goal
wp_live
2 opendeferred goal
iApply wpc_write_ PLivebase, VLivemkRegionbase base + 16 Heap Live ++ PAuxbase 0, VAuxCNone ++ cellbase 0 0 PLivebase, VLivemkRegionbase base + 16 Heap Live ++ PAuxbase 0, VAuxptr_caph ++ cellbase 0 ptr_addrh with [Hlv Hax Hc0] ; reflexivity | reflexivity | let m ≔ fresh "m" in intros m Hf & Hd & _ ; apply all_agree_app in Hf as Hf _ ; cbn [ all_agree fst snd agree_piece ] in Hf ; destruct Hf as Hlive _ ; pose proof Hlive as Hor _ ; split ; compute_eq | ; cbv beta ; eapply ptr_store_ok ; exact Hd | exact Hlive | cbn ; lia | lia | rewrite ! pts_app ; iFrame | iNext ; iIntros Hps ; iDestruct pts_app with Hps as [Hlv Hps] ; iDestruct pts_app with Hps as [Hax Hc0] ; gen_env
2 opendeferred goal
wp_emp
2 opendeferred goal
wp_emp
2 opendeferred goal
wp_live
2 opendeferred goal
iApply wpc_write_ PLivebase, VLivemkRegionbase base + 16 Heap Live ++ cellbase 8 0 PLivebase, VLivemkRegionbase base + 16 Heap Live ++ cellbase 8 i with [Hlv Hc8];
2 opendeferred goal
wp_emp
2 opendeferred goal
wp_emp
2 opendeferred goal
wp_fuel
2 opendeferred goal
wp_emp
2 opendeferred goal
iApply IH $! _ i + 1 mkPtrbase Objbase i :: xs with [%] [Hlv Hax Hc0 Hc8 Hl]
3 openfocused goal
deferred goal
{split ; eassumption |
3 opendeferred goal
deferred goal
split ; lia |
3 opendeferred goal
deferred goal
split ; eassumption
2 opendeferred goal
deferred goal
{cbn [ lst ]
2 opendeferred goal
iExists base, h
2 opendeferred goal
iSplitR ; iPureIntro ; split ; reflexivity | ; lia |
2 opendeferred goal
iFrame Hl
2 opendeferred goal
rewrite / node_ps ! pts_app
2 opendeferred goal
iFrame
deferred goal
–wp_emp
wp_fuel
wp_emp
wp_emp
iApply sum_spec with Hl
iIntros y fuel′
cbn [ fr_fn fr_env fr_locals fr_doomed fr_at ]
gen_env
iApply wpc_done_ emp%I _ _ _ Ret_ with [//] ; intros | let m ≔ fresh "m" in let s ≔ fresh "s" in iIntros m s _ _ ; iPureIntro ; compute_eq
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
listsum called with the int n is safe, with any fuel.
Explore proof 12 tactics
Initial goal
iStartProof
wp_fuel
wp_emp
wp_emp
wp_fuel
wp_emp
iApply ls_loopn $! _ _ _ [ ] with [%] []
4 openfocused goal
shelved goal
–split ; reflexivity |
3 opendeferred goal
split ; lia |
3 opendeferred goal
split ; reflexivity
–cbn [ lst ]
done
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
The resources the proof uses: invariants and the ghost heap.
lsΣ has invariants.
Explore proof 2 tactics
lsΣ has the ghost heap of pieces.
Explore proof 2 tactics
listsum never panics: for every input whose first word is an int, with any fuel, no state of its run fails, whatever bases its nodes get. Proved by Iris adequacy (heap_never_panics) from listsum_spec.
Explore proof 11 tactics
Initial goal
apply heap_never_panicslsΣ ls_module TAtom"listsum" _ ls_globals ls_mem ls_fn"listsum"
4 openfocused goal
–exact ls_initial
3 opendeferred goal
–exact ls_find_listsumR.free
2 opendeferred goal
–intros b1 r1 b2 r2 E _
2 openvm_compute in E
2 opendiscriminate E
–intros xs n & rest & →
eexists
2 opensplit ; apply listsum_call_frame |
intros fuel HinvG HheapG
apply listsum_spec
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.