Fil-C on Nix

Filnix wiki

the formal campaign

rocq/theories/Cycle.v

A loop whose trip count is the input, proved never to panic: rocq/programs/cycle.c, the sum of n longs read in turn from a read-only global array of four, xs[i % 4] for i from 0 while i < n, for every int n (CycleCode.v, checked current by rocq/programs.sh). The loop runs up to 2^31 - 1 times, so no list of runs covers it, as Prefix.v's six runs cover its loop.

The proof is Floyd's: an assertion at each point of the function (cycle_assert) says what the temporaries hold there, and one step from any configuration where the assertion holds reaches a point where its assertion holds, or ends without a failure (cycle_safe). Each step is taken by its rule from StepRules.v (Symbolic.v's take_step): the rule of the instruction at the point, with its premises (a temporary's value, an op on words, an access check) proved one by one. The loop's assertion is that its index i is between 0 and 2^31 - 1: then i % 4 is between 0 and 3, the access is in bounds, and i + 1 does not wrap. The index stays below 2^31 because the loop continues only while i < n, and no int n is above 2^31 - 1. Panics.v's never_panics_by_invariant turns that into never_panics.

Decisions

DecisionWhy
assertions at every point, not only at the loop's headthe machine's invariant must hold in every state a run reaches, and the safepoint at the poll edge may act in the middle of the loop
an assertion names only the temporaries read later, each with a rangethe environment stays abstract, so the proof holds whatever else it holds, in the first iteration and in every later one
the input is any list whose first word is an integerthe model reads an int parameter modulo 2^32, so no range on the word is needed; a pointer there is outside the C type
memory as in Sum.v's mem_okthe array is laid out where sum.c's is, and the program only reads it
From Stdlib Require Import String ZArith List Bool Lia
From Nanofil Require Import Term Syntax Values Memory Runtime Ops Semantics Run Machine Transport Panics Symbolic CycleCode Sum
Import ListNotations
Open Scope Z_scope
Arguments Z.add : simpl nomatch
Arguments Z.sub : simpl nomatch
Arguments Z.mul : simpl nomatch
Arguments Z.opp : simpl nomatch

Integer arithmetic on an unknown stays folded when a step is computed (Symbolic.v).

The program

The checked module, decoded from the fixture cycle_term (cycle_decodes).

49Definition cycle_module: module ≔
Somemd
⇒
md
None
⇒
[ ]

The fixture decodes to cycle_module.

53Lemma cycle_decodes
Explore proof 2 tactics

Initial goal

vm_compute

⊢
SomeIFuncfn_name ≔ TAtom"cycle"; fn_linkage ≔ TAtom"export"; fn_ret ≔ RClassL; fn_params ≔ W, TAtom"v0"; fn_blocks ≔ b_label ≔ TAtom"start"; b_phis ≔ [ ]; b_insts ≔ [ ]; b_jump ≔ JGotoToTAtom"L4"; b_label ≔ TAtom"L4"; b_phis ≔ PhiTAtom"pr.2" W TAtom"L5", TmpTAtom"v21"; TAtom"start", Const0; PhiTAtom"pr.1" L TAtom"L5", TmpTAtom"v19"; TAtom"start", Const0; b_insts ≔ LetTAtom"v10" W CmpSlt W TmpTAtom"pr.2"; TmpTAtom"v0"; b_jump ≔ JBranchTmpTAtom"v10" ToTAtom"L5" ToTAtom"L7"; b_label ≔ TAtom"L5"; b_phis ≔ [ ]; b_insts ≔ LetTAtom"v12" P Copy GlobalTAtom"xs"; LetTAtom"v14" W Rem TmpTAtom"pr.2"; Const4; LetTAtom"v15" L ExtSw TmpTAtom"v14"; LetTAtom"v16" L Shl TmpTAtom"v15"; Const3; FlightTAtom"v17" Add FAddressTmpTAtom"v12"; FValueTmpTAtom"v16" LowerOfTmpTAtom"v12"; LetTAtom"chk0" A Check0 8 Read 1 TmpTAtom"v17"; LetTAtom"v18" L RawLoadLdL 0 TmpTAtom"chk0"; LetTAtom"v19" L Add TmpTAtom"pr.1"; TmpTAtom"v18"; LetTAtom"v21" W Add TmpTAtom"pr.2"; Const1; b_jump ≔ JGotoPollTAtom"L4"; b_label ≔ TAtom"L7"; b_phis ≔ [ ]; b_insts ≔ [ ]; b_jump ≔ JRetTmpTAtom"pr.1"; IDataTAtom"xs" LRoTAtom"local" 8 Str1; 0; 0; 0; 0; 0; 0; 0; 2; 0; 0; 0; 0; 0; 0; 0; 3; 0; 0; 0; 0; 0; 0; 0; 4; 0; 0; 0; 0; 0; 0; 0 = SomeIFuncfn_name ≔ TAtom"cycle"; fn_linkage ≔ TAtom"export"; fn_ret ≔ RClassL; fn_params ≔ W, TAtom"v0"; fn_blocks ≔ b_label ≔ TAtom"start"; b_phis ≔ [ ]; b_insts ≔ [ ]; b_jump ≔ JGotoToTAtom"L4"; b_label ≔ TAtom"L4"; b_phis ≔ PhiTAtom"pr.2" W TAtom"L5", TmpTAtom"v21"; TAtom"start", Const0; PhiTAtom"pr.1" L TAtom"L5", TmpTAtom"v19"; TAtom"start", Const0; b_insts ≔ LetTAtom"v10" W CmpSlt W TmpTAtom"pr.2"; TmpTAtom"v0"; b_jump ≔ JBranchTmpTAtom"v10" ToTAtom"L5" ToTAtom"L7"; b_label ≔ TAtom"L5"; b_phis ≔ [ ]; b_insts ≔ LetTAtom"v12" P Copy GlobalTAtom"xs"; LetTAtom"v14" W Rem TmpTAtom"pr.2"; Const4; LetTAtom"v15" L ExtSw TmpTAtom"v14"; LetTAtom"v16" L Shl TmpTAtom"v15"; Const3; FlightTAtom"v17" Add FAddressTmpTAtom"v12"; FValueTmpTAtom"v16" LowerOfTmpTAtom"v12"; LetTAtom"chk0" A Check0 8 Read 1 TmpTAtom"v17"; LetTAtom"v18" L RawLoadLdL 0 TmpTAtom"chk0"; LetTAtom"v19" L Add TmpTAtom"pr.1"; TmpTAtom"v18"; LetTAtom"v21" W Add TmpTAtom"pr.2"; Const1; b_jump ≔ JGotoPollTAtom"L4"; b_label ≔ TAtom"L7"; b_phis ≔ [ ]; b_insts ≔ [ ]; b_jump ≔ JRetTmpTAtom"pr.1"; IDataTAtom"xs" LRoTAtom"local" 8 Str1; 0; 0; 0; 0; 0; 0; 0; 2; 0; 0; 0; 0; 0; 0; 0; 3; 0; 0; 0; 0; 0; 0; 0; 4; 0; 0; 0; 0; 0; 0; 0

reflexivity

No remaining goals.

Qed

✓ Proof checked and closed by Rocq.

Source script
vm_compute
reflexivity

The function cycle, the module's first item.

57Definition cycle_fn: func ≔
match cycle_module with
IFuncf :: _
⇒
f
_
⇒
mkFuncTAtom"cycle" TAtom"export" RClassL [ ] [ ]

The module's globals: the array xs, laid out as in Sum.v, and the function cycle.

65Definition cycle_globals: listname × ptr ≔
TAtom"xs", mkPtr65552 Ro65552; TAtom"cycle", mkPtr65536 FnTAtom"cycle"

The module's initial memory.

69Definition cycle_mem: mem ≔
Some_, m
⇒
m
None
⇒

Laying out the module succeeds, with cycle_globals and cycle_mem.

Explore proof 3 tactics

Initial goal

assert H : option_mapfst initial_memorycycle_module = Somecycle_globals by vm_compute ; reflexivity

unfold cycle_mem

destruct initial_memorycycle_module as g m | ; inversion H ; reflexivity

No remaining goals.

Qed

✓ Proof checked and closed by Rocq.

Source script
assert H : option_mapfst initial_memorycycle_module = Somecycle_globals by vm_compute ; reflexivity
unfold cycle_mem
destruct initial_memorycycle_module as g m | ; inversion H ; reflexivity

The genv of the module with any free; the program calls none.

82Definition cycle_gefree : word → mem → optionresunit × mem : genv ≔

cycle is a function of the core subset in the module.

86Lemma cycle_find
∀ free
Explore proof 3 tactics

Initial goal

⊢
∀free : word → mem → optionresunit × mem, find_fncycle_gefree TAtom"cycle" = SomeDefinedcycle_fn

intros free

free :
word → mem → optionresunit × mem

vm_compute

free :
word → mem → optionresunit × mem
⊢
SomeDefinedfn_name ≔ TAtom"cycle"; fn_linkage ≔ TAtom"export"; fn_ret ≔ RClassL; fn_params ≔ W, TAtom"v0"; fn_blocks ≔ b_label ≔ TAtom"start"; b_phis ≔ [ ]; b_insts ≔ [ ]; b_jump ≔ JGotoToTAtom"L4"; b_label ≔ TAtom"L4"; b_phis ≔ PhiTAtom"pr.2" W TAtom"L5", TmpTAtom"v21"; TAtom"start", Const0; PhiTAtom"pr.1" L TAtom"L5", TmpTAtom"v19"; TAtom"start", Const0; b_insts ≔ LetTAtom"v10" W CmpSlt W TmpTAtom"pr.2"; TmpTAtom"v0"; b_jump ≔ JBranchTmpTAtom"v10" ToTAtom"L5" ToTAtom"L7"; b_label ≔ TAtom"L5"; b_phis ≔ [ ]; b_insts ≔ LetTAtom"v12" P Copy GlobalTAtom"xs"; LetTAtom"v14" W Rem TmpTAtom"pr.2"; Const4; LetTAtom"v15" L ExtSw TmpTAtom"v14"; LetTAtom"v16" L Shl TmpTAtom"v15"; Const3; FlightTAtom"v17" Add FAddressTmpTAtom"v12"; FValueTmpTAtom"v16" LowerOfTmpTAtom"v12"; LetTAtom"chk0" A Check0 8 Read 1 TmpTAtom"v17"; LetTAtom"v18" L RawLoadLdL 0 TmpTAtom"chk0"; LetTAtom"v19" L Add TmpTAtom"pr.1"; TmpTAtom"v18"; LetTAtom"v21" W Add TmpTAtom"pr.2"; Const1; b_jump ≔ JGotoPollTAtom"L4"; b_label ≔ TAtom"L7"; b_phis ≔ [ ]; b_insts ≔ [ ]; b_jump ≔ JRetTmpTAtom"pr.1" = SomeDefinedfn_name ≔ TAtom"cycle"; fn_linkage ≔ TAtom"export"; fn_ret ≔ RClassL; fn_params ≔ W, TAtom"v0"; fn_blocks ≔ b_label ≔ TAtom"start"; b_phis ≔ [ ]; b_insts ≔ [ ]; b_jump ≔ JGotoToTAtom"L4"; b_label ≔ TAtom"L4"; b_phis ≔ PhiTAtom"pr.2" W TAtom"L5", TmpTAtom"v21"; TAtom"start", Const0; PhiTAtom"pr.1" L TAtom"L5", TmpTAtom"v19"; TAtom"start", Const0; b_insts ≔ LetTAtom"v10" W CmpSlt W TmpTAtom"pr.2"; TmpTAtom"v0"; b_jump ≔ JBranchTmpTAtom"v10" ToTAtom"L5" ToTAtom"L7"; b_label ≔ TAtom"L5"; b_phis ≔ [ ]; b_insts ≔ LetTAtom"v12" P Copy GlobalTAtom"xs"; LetTAtom"v14" W Rem TmpTAtom"pr.2"; Const4; LetTAtom"v15" L ExtSw TmpTAtom"v14"; LetTAtom"v16" L Shl TmpTAtom"v15"; Const3; FlightTAtom"v17" Add FAddressTmpTAtom"v12"; FValueTmpTAtom"v16" LowerOfTmpTAtom"v12"; LetTAtom"chk0" A Check0 8 Read 1 TmpTAtom"v17"; LetTAtom"v18" L RawLoadLdL 0 TmpTAtom"chk0"; LetTAtom"v19" L Add TmpTAtom"pr.1"; TmpTAtom"v18"; LetTAtom"v21" W Add TmpTAtom"pr.2"; Const1; b_jump ≔ JGotoPollTAtom"L4"; b_label ≔ TAtom"L7"; b_phis ≔ [ ]; b_insts ≔ [ ]; b_jump ≔ JRetTmpTAtom"pr.1"

reflexivity

No remaining goals.

Qed

✓ Proof checked and closed by Rocq.

Source script
intros free
vm_compute
reflexivity

Any arguments whose first word is the integer n start cycle at its entry block with n as its parameter v0.

92Lemma cycle_call_frame
∀ n rest
call_framecycle_fn WIntn :: rest = SomemkFramecycle_fn TAtom"v0", WIntn [ ] None EnterTAtom"start" None
Explore proof 1 tactics

Initial goal

⊢
∀n : Z rest : listword, call_framecycle_fn WIntn :: rest = Somefr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None

reflexivity

No remaining goals.

Qed

✓ Proof checked and closed by Rocq.

Source script
reflexivity

The points

Block l of cycle after its first j instructions.

100Definition block_atl : string j : nat : point ≔
Someb
⇒
None
⇒

Every point of cycle, numbered: the entry block start; the loop's head L4 (entered from start or from the body, then its comparison of i with n, then its branch); the loop's body L5, before each of its nine instructions and before its jump back, which polls; and the exit L7, which returns the sum.

111Definition cycle_points: listpoint ≔
EnterTAtom"start" None; block_at"start" 0; EnterTAtom"L4" SomeTAtom"start"; EnterTAtom"L4" SomeTAtom"L5"; block_at"L4" 0; block_at"L4" 1; EnterTAtom"L5" SomeTAtom"L4" ++ mapblock_at"L5" seq0 10 ++ EnterTAtom"L7" SomeTAtom"L4"; block_at"L7" 0

The assertions

The temporary x holds a pointer into xs with 8 bytes after it: an address from the array's start to its last long, with the array's read-only capability.

123Definition into_xse : env x : string : Prop ≔
∃a, lookupTAtomx e = SomeWPtrmkPtra Ro65552 ∧ 65552 ≤ a ≤ 65576

What holds after the first j instructions of the body: the sum pr.1, the index pr.2 with room to add one, and each temporary the body has assigned and reads later: the array's pointer v12, i % 4 (v14, then v15 as a long), the offset v16, the pointer v17 and its checked proof chk0, the long loaded v18, the new sum v19 and the next index v21.

132Definition body_assertj : nat e : env : Prop ≔
∧
int_ate TAtom"pr.2" λi ⇒ 0 ≤ i ∧ i + 1 < 2 ^ 31
∧
1 ≤? j%nat
→
lookupTAtom"v12" e = SomeWPtrmkPtr65552 Ro65552
else
True
∧
2 ≤? j%nat
→
int_ate TAtom"v14" λr ⇒ 0 ≤ r < 4
else
True
∧
3 ≤? j%nat
→
int_ate TAtom"v15" λr ⇒ 0 ≤ r < 4
else
True
∧
4 ≤? j%nat
→
int_ate TAtom"v16" λo ⇒ 0 ≤ o ≤ 24
else
True
∧
5 ≤? j%nat
→
into_xse "v17"
else
True
∧
6 ≤? j%nat
→
into_xse "chk0"
else
True
∧
7 ≤? j%nat
→
else
True
∧
8 ≤? j%nat
→
else
True
∧
9 ≤? j%nat
→
int_ate TAtom"v21" λi ⇒ 0 ≤ i < 2 ^ 31
else
True

What holds at point k of cycle_points, besides the input. At the loop's head entered from the body, the next index and sum; before the comparison, the index i and the sum; at the branch, also the comparison's answer, and where it is true, that i + 1 does not reach 2^31, since i < n; in the body, body_assert; at the exit, the sum.

150Definition cycle_assertk : nat e : env : Prop ≔
match k with
3%nat
⇒
int_ate TAtom"v21" λi ⇒ 0 ≤ i < 2 ^ 31 ∧ int_ate TAtom"v19" any
4%nat
⇒
int_ate TAtom"pr.1" any ∧ int_ate TAtom"pr.2" λi ⇒ 0 ≤ i < 2 ^ 31
5%nat
⇒
int_ate TAtom"pr.1" any ∧ ∃i, lookupTAtom"pr.2" e = SomeWInti ∧ 0 ≤ i < 2 ^ 31 ∧ lookupTAtom"v10" e = SomeWInt0 ∨ lookupTAtom"v10" e = SomeWInt1 ∧ i + 1 < 2 ^ 31
6%nat
⇒
17%nat | 18%nat
⇒
_
⇒
7 ≤? k%nat && k ≤? 16%nat
→
body_assertk − 7 e
else
True

A configuration of cycle where the assertions hold: at point k, with no caller, the input v0 an integer, the assertion of k, and a memory that is mem_ok for the array.

166Definition cycle_invc : config : Prop ≔
∃k pt e, c = mkConfigmkFramecycle_fn e [ ] None pt [ ] c_memc c_fuelc ∧ nth_errorcycle_points k = Somept ∧ mem_okcycle_mem c_memc ∧ int_ate TAtom"v0" any ∧ cycle_assertk e

Each step

Unfold the assertion at a known point.

175Ltac assertion  ≔
cbn [ cycle_assert Nat.leb andb Nat.sub ] ; try unfold body_assert ; cbn [ Nat.leb ]

Unfold the assertion at a known point in the hypothesis H.

178Ltac assertion_in H ≔
cbn [ cycle_assert Nat.leb andb Nat.sub ] in H ; try unfold body_assert in H ; cbn [ Nat.leb ] in H

The point of the next configuration is point n of cycle_points or a later one: find it by computing each in turn.

183Ltac find_point pt n ≔
lazymatch n with19%nat⇒fail_⇒first assert Hpt : nth_errorcycle_points n = Somept by vm_compute ; reflexivity ; exists n, pt | find_point pt Snend

The next configuration is in cycle_inv: at its point, with the memory unchanged, and the facts shown.

193Ltac next_inv Hb Hr ≔
unfold cycle_inv;match goal with|- ∃k pt e, mkConfigmkFrame_ _ _ _ ?pt′ _ _ _ = _ ∧ _⇒find_point pt′ 0%natend;eexists;split;|subst ; reflexivity|;split;|assumption|;cbn [ c_mem ];split;|exact conjHb Hr|;split;|show_facts|assertion ; try unfold into_xs ; show_facts

One point of cycle_safe: the point from Hk, an index into the points pts, the assertion Ha taken apart, the step taken by its rule (take_step), and its result shown safe.

204Ltac point_safe pts Hk Ha Hb Hr ≔
cbv in Hk ; injection Hk as ← ; clear pts ; assertion_in Ha ; unfold int_at , into_xs in * ; facts ; take_step ; cbn [ safe_step ] ; solve intro ; assumption | next_inv Hb Hr

One step from a configuration where the assertions hold is safe_step for them.

212Lemma cycle_safe
Proof 18 steps Qed
intros free c k & pt & e & Ec & Hk & Hm & Hin & Ha
rewrite Ec
destruct Hm as Hb Hr
unfold xs_region in Hr
clear Ec
set m := c_memc in *
set fuel := c_fuelc in *
clearbody m fuel
set pts := cycle_points in Hk
vm_compute in pts
remember cycle_fn as f eqn: Hf
block_fact f cycle_fn Hf TAtom"start" b0 Hb0
block_fact f cycle_fn Hf TAtom"L4" b4 Hb4
block_fact f cycle_fn Hf TAtom"L5" b5 Hb5
block_fact f cycle_fn Hf TAtom"L7" b7 Hb7
assert Hret : fn_retf = RClassL by rewrite Hf ; reflexivity
do 19 destruct k as | k ; point_safe pts Hk Ha Hb Hr |
destruct k ; discriminate Hk

A call with an integer first argument starts where the assertions hold, with any fuel.

230Lemma cycle_start
∀ n fuel
cycle_invmkConfigmkFramecycle_fn TAtom"v0", WIntn [ ] None EnterTAtom"start" None [ ] cycle_mem fuel
Explore proof 6 tactics

Initial goal

⊢
∀n fuel : Z, cycle_invc_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel

intros n fuel

n, fuel :
Z
⊢
cycle_invc_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel

exists O, EnterTAtom"start" None, TAtom"v0", WIntn

n, fuel :
Z
⊢
c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel = c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None; c_callers ≔ [ ]; c_mem ≔ c_memc_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel; c_fuel ≔ c_fuelc_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel ∧ nth_errorcycle_points 0 = SomeEnterTAtom"start" None ∧ mem_okcycle_mem c_memc_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel ∧ int_atTAtom"v0", WIntn TAtom"v0" any ∧ cycle_assert0 TAtom"v0", WIntn

split ; reflexivity |

n, fuel :
Z
⊢
nth_errorcycle_points 0 = SomeEnterTAtom"start" None ∧ mem_okcycle_mem c_memc_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel ∧ int_atTAtom"v0", WIntn TAtom"v0" any ∧ cycle_assert0 TAtom"v0", WIntn

split ; vm_compute ; reflexivity |

n, fuel :
Z
⊢
mem_okcycle_mem c_memc_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel ∧ int_atTAtom"v0", WIntn TAtom"v0" any ∧ cycle_assert0 TAtom"v0", WIntn

split ; split ; reflexivity | vm_compute ; reflexivity |

n, fuel :
Z
⊢

split ; exists n ; split ; reflexivity | exact I | exact I

No remaining goals.

Qed

✓ Proof checked and closed by Rocq.

Source script
intros n fuel
exists O, EnterTAtom"start" None, TAtom"v0", WIntn
split ; reflexivity |
split ; vm_compute ; reflexivity |
split ; split ; reflexivity | vm_compute ; reflexivity |
split ; exists n ; split ; reflexivity | exact I | exact I

Over any runtime

cycle never panics under the runtime R.

243Module CycleSafe R : Runtime
244Module P ≔ Panics R
245Module S ≔ SumSafe R

What R does at a safepoint keeps the assertions: it changes only the memory, and keeps mem_ok (Sum.v's mem_ok_safepoint).

250Lemma cycle_safepoint
∀ c s s′ m′
R.safepoints c_memc s′ m′
Explore proof 8 tactics

Initial goal

⊢
∀c : config s s′ : R.state m′ : mem, cycle_invc → R.safepoints c_memc s′ m′ → cycle_invP.RM.with_memc m′

intros c s s′ m′ k & pt & e & Ec & Hk & Hm & Hin & Ha Hsp

s, s′ :
R.state
m′ :
k :
nat
pt :
e :
Ec :
c = c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ c_memc; c_fuel ≔ c_fuelc
Hk :
nth_errorcycle_points k = Somept
Hin :
Hsp :
R.safepoints c_memc s′ m′

exists k, pt, e

s, s′ :
R.state
m′ :
k :
nat
pt :
e :
Ec :
c = c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ c_memc; c_fuel ≔ c_fuelc
Hk :
nth_errorcycle_points k = Somept
Hin :
Hsp :
R.safepoints c_memc s′ m′
⊢
P.RM.with_memc m′ = c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ c_memP.RM.with_memc m′; c_fuel ≔ c_fuelP.RM.with_memc m′ ∧ nth_errorcycle_points k = Somept ∧ mem_okcycle_mem c_memP.RM.with_memc m′ ∧ int_ate TAtom"v0" any ∧ cycle_assertk e

rewrite Ec at 1

s, s′ :
R.state
m′ :
k :
nat
pt :
e :
Ec :
c = c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ c_memc; c_fuel ≔ c_fuelc
Hk :
nth_errorcycle_points k = Somept
Hin :
Hsp :
R.safepoints c_memc s′ m′
⊢
P.RM.with_memc_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ c_memc; c_fuel ≔ c_fuelc m′ = c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ c_memP.RM.with_memc m′; c_fuel ≔ c_fuelP.RM.with_memc m′ ∧ nth_errorcycle_points k = Somept ∧ mem_okcycle_mem c_memP.RM.with_memc m′ ∧ int_ate TAtom"v0" any ∧ cycle_assertk e

unfold P.RM.with_mem ; cbn [ c_frame c_callers c_mem c_fuel ]

s, s′ :
R.state
m′ :
k :
nat
pt :
e :
Ec :
c = c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ c_memc; c_fuel ≔ c_fuelc
Hk :
nth_errorcycle_points k = Somept
Hin :
Hsp :
R.safepoints c_memc s′ m′
⊢
c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ m′; c_fuel ≔ c_fuelc = c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ m′; c_fuel ≔ c_fuelc ∧ nth_errorcycle_points k = Somept ∧ mem_okcycle_mem m′ ∧ int_ate TAtom"v0" any ∧ cycle_assertk e

split ; reflexivity |

s, s′ :
R.state
m′ :
k :
nat
pt :
e :
Ec :
c = c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ c_memc; c_fuel ≔ c_fuelc
Hk :
nth_errorcycle_points k = Somept
Hin :
Hsp :
R.safepoints c_memc s′ m′
⊢
nth_errorcycle_points k = Somept ∧ mem_okcycle_mem m′ ∧ int_ate TAtom"v0" any ∧ cycle_assertk e

split ; exact Hk |

s, s′ :
R.state
m′ :
k :
nat
pt :
e :
Ec :
c = c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ c_memc; c_fuel ≔ c_fuelc
Hk :
nth_errorcycle_points k = Somept
Hin :
Hsp :
R.safepoints c_memc s′ m′
⊢

split ; | split ; assumption

s, s′ :
R.state
m′ :
k :
nat
pt :
e :
Ec :
c = c_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ e; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ pt; c_callers ≔ [ ]; c_mem ≔ c_memc; c_fuel ≔ c_fuelc
Hk :
nth_errorcycle_points k = Somept
Hin :
Hsp :
R.safepoints c_memc s′ m′

eapply S.mem_ok_safepoint ; eassumption

No remaining goals.

Qed

✓ Proof checked and closed by Rocq.

Source script
intros c s s′ m′ k & pt & e & Ec & Hk & Hm & Hin & Ha Hsp
exists k, pt, e
rewrite Ec at 1
split ; reflexivity |
split ; exact Hk |
split ; | split ; assumption
eapply S.mem_ok_safepoint ; eassumption

cycle never panics: for every input whose first word is an integer, under the runtime R, with any fuel, no state of its run fails, however many times the loop runs.

262Theorem cycle_never_panics
P.never_panicscycle_module TAtom"cycle" λxs ⇒ ∃n rest, xs = WIntn :: rest
Explore proof 12 tactics

Initial goal

⊢
P.never_panicscycle_module TAtom"cycle" λxs : listword ⇒ ∃n : Z rest : listword, xs = WIntn :: rest

apply P.never_panics_by_invariant_ _ _ cycle_globals cycle_mem cycle_fn cycle_inv

5 open

focused goal
focused goal
⊢
∀xs : listword, ∃n : Z rest : listword, xs = WIntn :: rest → ∃fr : frame, call_framecycle_fn xs = Somefr ∧ ∀fuel : Z, cycle_invc_frame ≔ fr; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel
focused goal
focused goal
⊢
∀c : config s s′ : R.state m′ : mem, cycle_invc → R.readys c_memc → P.RM.safepoint_dueP.program_genvcycle_module cycle_globals c = true → R.safepoints c_memc s′ m′ → cycle_invP.RM.with_memc m′

–exact cycle_initial

4 open

deferred goal
deferred goal
⊢
∀xs : listword, ∃n : Z rest : listword, xs = WIntn :: rest → ∃fr : frame, call_framecycle_fn xs = Somefr ∧ ∀fuel : Z, cycle_invc_frame ≔ fr; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel
deferred goal
deferred goal
⊢
∀c : config s s′ : R.state m′ : mem, cycle_invc → R.readys c_memc → P.RM.safepoint_dueP.program_genvcycle_module cycle_globals c = true → R.safepoints c_memc s′ m′ → cycle_invP.RM.with_memc m′

–apply cycle_find

3 open

deferred goal
⊢
∀xs : listword, ∃n : Z rest : listword, xs = WIntn :: rest → ∃fr : frame, call_framecycle_fn xs = Somefr ∧ ∀fuel : Z, cycle_invc_frame ≔ fr; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel
deferred goal
deferred goal
⊢
∀c : config s s′ : R.state m′ : mem, cycle_invc → R.readys c_memc → P.RM.safepoint_dueP.program_genvcycle_module cycle_globals c = true → R.safepoints c_memc s′ m′ → cycle_invP.RM.with_memc m′

–intros xs n & rest & →

3 open

n :
Z
rest :
listword
⊢
∃fr : frame, call_framecycle_fn WIntn :: rest = Somefr ∧ ∀fuel : Z, cycle_invc_frame ≔ fr; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel
deferred goal
deferred goal
⊢
∀c : config s s′ : R.state m′ : mem, cycle_invc → R.readys c_memc → P.RM.safepoint_dueP.program_genvcycle_module cycle_globals c = true → R.safepoints c_memc s′ m′ → cycle_invP.RM.with_memc m′

eexists

4 open

n :
Z
rest :
listword
⊢
call_framecycle_fn WIntn :: rest = Some?fr ∧ ∀fuel : Z, cycle_invc_frame ≔ ?fr; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel
deferred goal
deferred goal
⊢
∀c : config s s′ : R.state m′ : mem, cycle_invc → R.readys c_memc → P.RM.safepoint_dueP.program_genvcycle_module cycle_globals c = true → R.safepoints c_memc s′ m′ → cycle_invP.RM.with_memc m′
shelved goal
n :
Z
rest :
listword

split ; apply cycle_call_frame |

3 open

n :
Z
rest :
listword
⊢
∀fuel : Z, cycle_invc_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel
deferred goal
deferred goal
⊢
∀c : config s s′ : R.state m′ : mem, cycle_invc → R.readys c_memc → P.RM.safepoint_dueP.program_genvcycle_module cycle_globals c = true → R.safepoints c_memc s′ m′ → cycle_invP.RM.with_memc m′

intros fuel

3 open

n :
Z
rest :
listword
fuel :
Z
⊢
cycle_invc_frame ≔ fr_fn ≔ cycle_fn; fr_env ≔ TAtom"v0", WIntn; fr_locals ≔ [ ]; fr_doomed ≔ None; fr_at ≔ EnterTAtom"start" None; c_callers ≔ [ ]; c_mem ≔ cycle_mem; c_fuel ≔ fuel
deferred goal
deferred goal
⊢
∀c : config s s′ : R.state m′ : mem, cycle_invc → R.readys c_memc → P.RM.safepoint_dueP.program_genvcycle_module cycle_globals c = true → R.safepoints c_memc s′ m′ → cycle_invP.RM.with_memc m′

apply cycle_start

2 open

deferred goal
deferred goal
⊢
∀c : config s s′ : R.state m′ : mem, cycle_invc → R.readys c_memc → P.RM.safepoint_dueP.program_genvcycle_module cycle_globals c = true → R.safepoints c_memc s′ m′ → cycle_invP.RM.with_memc m′

–intros c s Hc _

2 open

deferred goal
⊢
∀c : config s s′ : R.state m′ : mem, cycle_invc → R.readys c_memc → P.RM.safepoint_dueP.program_genvcycle_module cycle_globals c = true → R.safepoints c_memc s′ m′ → cycle_invP.RM.with_memc m′

apply cycle_safe , Hc

deferred goal
⊢
∀c : config s s′ : R.state m′ : mem, cycle_invc → R.readys c_memc → P.RM.safepoint_dueP.program_genvcycle_module cycle_globals c = true → R.safepoints c_memc s′ m′ → cycle_invP.RM.with_memc m′

–intros c s s′ m′ Hc _ _ Hsp

s, s′ :
R.state
m′ :
Hsp :
R.safepoints c_memc s′ m′

eapply cycle_safepoint ; eassumption

No remaining goals.

Qed

✓ Proof checked and closed by Rocq.

Source script
–exact cycle_initial
–apply cycle_find
–intros xs n & rest & →
eexists
split ; apply cycle_call_frame |
intros fuel
–intros c s Hc _
apply cycle_safe , Hc
–intros c s s′ m′ Hc _ _ Hsp
eapply cycle_safepoint ; eassumption

The theorem for the interpreter's runtime.

276Module InterpCycle ≔ CycleSafe InterpRuntime