rocq/theories/Soundness.v
Campaign 3's theorem, valid_no_unchecked: if the validator accepts a module, no run of it that starts ready ever steps to unchecked (formal.md, Campaign 3; rocq.md, No run is unchecked).
The interpreter's unchecked(Reason) is the outcome a validated module must never reach: it marks a raw access or a reuse form the validator accepted but whose justification was false at run time. So the theorem says the validator's checks are sound: every access it lets go unchecked is in fact in bounds, or traps as a checked access would. It rests on the runtime axioms of Runtime.v and on the run starting ready; the runtime's safepoints spare the pass's facts for every runtime (Invariant.v's spares_any), and the interpreter's instance is interp_valid_no_unchecked. The validator here is Validate.v's transcription, which the gates compare with ir:valid_module/1; external calls other than free are stuck in the model, so the theorem says nothing about a run past one. The proof is assembled from the run theorems, one per place an unchecked can come from:
| Source | Run theorem |
|---|---|
| a raw load, store or call | Chain.v's run_access_checked |
| a renew, a renew over a hull, a half check | Renew.v's run_reuse_checked |
a renew_if, a check_limit | Guard.v's run_guard_checked |
a frame a check_ahead doomed | Doomed.v's run_doomed_checked |
| the runtime's free | Runtime.v's axiom free_checked |
Decisions
| Decision | Why |
|---|---|
free never answering unchecked is the module type's axiom free_checked | mbrock's decision, with the native test axiom-free.c |
| the theorem takes no hypothesis about safepoints | every runtime spares the pass's facts (Invariant.v's spares_any); spares was a hypothesis until 2026-11-09, while a handler's free at a pointer store's aux exit counted as the runtime's (The runtime's safepoints) |
| a run is stated over Guard.v's machine instance | the doomed frame's run is carried over to Doomed.v's (mreachable_doom) |
Where unchecked comes from
The ops o whose result may be unchecked: a raw load, whose access the check before it covers (raw_res/2), or a reuse form (renew, renew over a hull, half check, renew_if, check_limit), whose source or limit may not be the one the pass took.
No op but an unchecked_op answers unchecked (kind_res/8): a check answers its access check, which traps or passes.
Explore proof 8 tactics
Initial goal
intros o k xs m r m′ H
destruct o ; try reflexivity ; exfalso
36 openfocused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
focused goal
all: unfold op_res , op_res_int in H ; cases H
7 openfocused goal
focused goal
focused goal
focused goal
focused goal
focused goal
all: try discriminate H
3 openfocused goal
all: try (match goal withE : access_res_ _ _ _ _ _ = SomeRUnchecked_ |- _⇒exact access_res_checked_ _ _ _ _ _ _ E _ eq_reflend)
3 openfocused goal
all: try (match goal withE : access_res_ _ _ _ _ _ = Some |- _⇒destruct x ; cbn [ checked_res ] in H ; try discriminate H ; exact access_res_checked_ _ _ _ _ _ _ E _ eq_reflend)
2 openall: try unfold float_integer in H ; cases H ; fail
all: match goal withE : va_arg_res_ _ _ = Some |- _⇒injection H as H3 _ ; exact va_arg_reason_ _ _ _ _ E H3end
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
An instruction i's result is unchecked only as a let of an unchecked_op, a raw store, a raw call, or a call of free that the runtime's free (ge_free) answered so (inst_result/5).
Proof 68 steps Qed
Raw accesses go through a temporary
A raw load or store i of a function of a checked_module md reads its address from a temporary, so the validator saw it as a raw access (raw_access is not None, raw_access/5): valid_use/3 reads no global at the proof class a and no constant at a proof class.
Explore proof 16 tactics
Initial goal
intros md f b i Hmd Hin Hb Hi Hr
destruct inst_valid_ _ _ _ Hmd Hin Hb Hi as cls Hvi
destruct Hr as q & k & t & off & args & → | q & k & off & es & args & → | wd & off & v & a & → | off & v & a & es & →
4 openfocused goal
focused goal
focused goal
–destruct k ; destruct args as | n | n | g | v2 args ; simpl in Hvi;repeat match goal withH : _ && _ = true |- _⇒apply andb_true_iff in H as ? ?end;try discriminate;simpl;discriminate
3 opendeferred goal
deferred goal
deferred goal
–destruct k ; destruct args as | n | n | g | v2 args ; simpl in Hvi;repeat match goal withH : _ && _ = true |- _⇒apply andb_true_iff in H as ? ?end;try discriminate;simpl;discriminate
2 opendeferred goal
deferred goal
–simpl in Hvi
2 opendeferred goal
destruct width_value_okwd ; | discriminate Hvi
2 opendeferred goal
apply andb_true_iff in Hvi as _ Hvi
2 opendeferred goal
destruct a as n | n | g ; simpl in Hvi ; try discriminate Hvi
2 opendeferred goal
simpl
2 opendeferred goal
discriminate
deferred goal
–simpl in Hvi
apply andb_true_iff in Hvi as _ Hvi
destruct a as n | n | g ; simpl in Hvi ; try discriminate Hvi
simpl
discriminate
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A step that is not doomed
In a frame fr that is not doomed, doomed_result/5 keeps an instruction's result out as it is, or goes on.
Explore proof 4 tactics
Initial goal
intros ge fr m i out od Hd H
unfold doomed_result in H
rewrite Hd in H
cases H ; injection H as ← ; simpl ; first left ; reflexivity | right ; do 3 eexists ; reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A return that ends the run ends it with the outcome o it returns, not another (call_outcome_result/5).
Explore proof 5 tactics
Initial goal
unfold return_step , or_stuck
intros c o o′ H
cases H
all: repeat match goal withE : Some_ = Some_ |- _⇒injection E as EE : = Done_ |- _⇒is_var x ; subst xE : context [match _ with _ ⇒ _ end] |- _⇒progress cases Eend
all: congruence
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A frame that is not doomed steps to unchecked only where its next instruction i's result is: a block's entry, a jump and a return give no such outcome (block_outcome/7, jump_outcome/7).
Explore proof 27 tactics
Initial goal
intros ge c w Hd H
unfold step in H
destruct fr_atc_framec as xs l | l from | l | i rest j eqn: Ha
4 openfocused goal
focused goal
–destruct xs ; discriminate H |
4 opendeferred goal
deferred goal
destruct negb_ ; discriminate H
3 opendeferred goal
deferred goal
–destruct c_fuelc =? 0 ; discriminate H |
3 opendeferred goal
deferred goal
unfold or_stuck in H
3 opendeferred goal
deferred goal
destruct find_blockl _ ; simpl in H ; | discriminate H
3 opendeferred goal
deferred goal
destruct phis_env_ _ _ _ ; simpl in H ; discriminate H
2 opendeferred goal
deferred goal
–exfalso
2 opendeferred goal
unfold jump_step , edge_step , or_stuck in H
2 opendeferred goal
rewrite Hd in H
2 opendeferred goal
cbv zeta in H
2 opendeferred goal
cases H
5 openfocused goal
focused goal
deferred goal
all: repeat match goal withE : Some_ = Some_ |- _⇒injection E as EE : return_step_ _ = Done_ |- _⇒apply return_step_done in E ; discriminate EE : = Done_ |- _⇒is_var x ; subst xE : context [match _ with _ ⇒ _ end] |- _⇒progress cases Eend
deferred goal
–rewrite Hd in H
cbv zeta in H
destruct inst_stepge c_framec c_memc i as out0 | eqn: Ei ; | discriminate H
simpl in H
destruct doomed_resultge c_framec c_memc i out0 as od | eqn: Eo ; | discriminate H
simpl in H
apply inst_next_done in H
destruct undoomed_result_ _ _ _ _ _ Hd Eo as Ho | e & locals & m′ & Ho ; rewrite H in Ho ; | discriminate Ho
exists l, i, rest, j
split ; reflexivity |
rewrite Ei , Ho
reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Along a run
The theorem for any runtime R that meets Runtime.v's module type.
A step of Guard.v's machine instance, the one Chain.v's, Renew.v's and Guard.v's run theorems share, is a step of Doomed.v's.
Explore proof 2 tactics
Initial goal
intros ge st st′ H
destruct H ; econstructor ; eassumption
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A run of Guard.v's machine instance is a run of Doomed.v's, so run_doomed_checked applies to it.
Explore proof 6 tactics
Initial goal
intros ge st st′ H
induction H as st st′ H | st | st1 st2 st3 _ IH1 _ IH2
3 openfocused goal
focused goal
–apply rt_step
3 opendeferred goal
deferred goal
exact mstep_doom_ _ _ H
2 opendeferred goal
deferred goal
–apply rt_refl
deferred goal
–exact rt_trans_ _ _ _ _ IH1 IH2
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Soundness of checking. Take a module md the validator accepts (checked_module), a function f of it called with arguments xs, and a memory m where the runtime R is ready. In every state c a run reaches from that call, the next step is not unchecked: every access the checked code did not check was in bounds or trapped as a check would. It rests on Runtime.v's axioms (among them free_checked: free never answers unchecked); every runtime spares the pass's facts at safepoints (spares_any; see The evidence invariant over runs). The proof sends a doomed frame to run_doomed_checked, and any other to the run theorem for its instruction.
Proof 29 steps Qed
The interpreter's runtime
The theorem for the interpreter's runtime.
valid_no_unchecked for the interpreter's runtime: in every state of a run of a checked module's function that starts ready, no step is unchecked. No hypothesis remains but the ready start; Print Assumptions reports it closed.
Explore proof 2 tactics
Initial goal
intros md globals f xs fr m fuel s0 c s w ge Hmd Hin Hcf H0 Hreach
exact InterpSound.valid_no_uncheckedge md f xs fr m fuel s0 c s w Hmd eq_refl eq_refl Hin Hcf H0 Hreach
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.