cap_machine.exercises.cerise_tutorial_solutions

This file is a tutorial to learn how to use the Cerise program logic in Coq. We will specify a simple program and explain the tactic to use to prove the specification. We assume the user already knows how to use Iris, for instance with Heaplang.

From iris.proofmode Require Import tactics.
From cap_machine Require Import rules.
From cap_machine.proofmode Require Import proofmode tactics_helpers contiguous.
Open Scope Z_scope.

Section base_program.
  Context {Σ:gFunctors} {memg:memG Σ} {regg:regG Σ}
          `{MP: MachineParameters}.

  Definition prog_instrs : list Word :=
    encodeInstrsW [
      Lea r_t1 1 ;
      Store r_t1 r_t2 ].

Exercise 1 - More automation with iGo


  Lemma prog_spec_igo
    p_pc b_pc e_pc a_prog (* pc *)
    b_mem (* mem *)
    φ :

    let e_mem := (b_mem ^+ 2)%a in
    let e_prog := (a_prog ^+ length prog_instrs)%a in

    ExecPCPerm p_pc ->
    SubBounds b_pc e_pc a_prog e_prog ->
    ContiguousRegion b_mem 2

     ( PC ↦ᵣ WCap p_pc b_pc e_pc a_prog
         codefrag a_prog prog_instrs
         r_t1 ↦ᵣ WCap RW b_mem e_mem b_mem
         [[b_mem, e_mem]] ↦ₐ [[ [WInt 0; WInt 0] ]]
r_t2 ↦ᵣ WInt 42
          ( PC ↦ᵣ WCap p_pc b_pc e_pc e_prog
                 r_t1 ↦ᵣ WCap RW b_mem e_mem (b_mem ^+1)%a
                 r_t2 ↦ᵣ WInt 42
                 codefrag a_prog prog_instrs
                 [[b_mem, e_mem]] ↦ₐ [[ [WInt 0; WInt 42] ]]
-∗ WP Seq (Instr Executable) {{ φ }}))
       -∗ WP Seq (Instr Executable) {{ φ }}%I.
  Proof.
    intros * Hpc_perm Hpc_bounds Hmem_bounds.
    unfold ContiguousRegion in Hmem_bounds.
    iIntros "(HPC& Hprog& Hr1& Hmem& Hr2& Hcont)".
    subst e_mem e_prog; simpl.

    (* Derives the facts from the codefrag *)
    codefrag_facts "Hprog".
    simpl in *.

    (* Prepare the memory resource for the Store *)
    iDestruct (region_pointsto_cons with "Hmem") as "(Hmem0& Hmem1)".
    { transitivity (Some (b_mem ^+1)%a) ; auto ; by solve_addr. }
    { by solve_addr. }
    iDestruct (region_pointsto_single with "Hmem1") as "Hmem1".
    { transitivity (Some (b_mem ^+(1+1))%a) ; auto ; by solve_addr. }
    iDestruct "Hmem1" as (v) "(Hmem1& %Hr)".
    injection Hr ; intro Hr' ; subst ; clear Hr.

    (* 2 - step through multiple instructions *)
    iGo "Hprog".

    (* 3 - Continuation *)
    iApply "Hcont".
    iFrame.
    iApply region_pointsto_cons.
    { transitivity (Some (b_mem ^+1)%a) ; auto ; by solve_addr. }
    { by solve_addr. }
    iFrame.
    iApply region_pointsto_cons.
    { transitivity (Some (b_mem ^+(1+1))%a) ; auto ; by solve_addr. }
    { by solve_addr. }
    iFrame.
    replace (b_mem ^+ (1 + 1))%a with (b_mem ^+ 2)%a by solve_addr.
    unfold region_pointsto.
    rewrite finz_seq_between_empty ; last solve_addr.
    done.
  Unshelve. Fail idtac. Admitted.

Exercise 2 --- Manual detailled proofs


  Lemma prog_spec_detailed
    p_pc b_pc e_pc (* pc *)
    a_prog a
    b_mem (* mem *)
    φ :

    let e_mem := (b_mem ^+ 2)%a in
    let e_prog := (a_prog ^+ length prog_instrs)%a in

    ExecPCPerm p_pc ->
    SubBounds b_pc e_pc a_prog e_prog ->
    contiguous_between a a_prog (e_prog)
    ContiguousRegion b_mem 2

     ( PC ↦ᵣ WCap p_pc b_pc e_pc a_prog
         ([∗ list] a_i;w a;prog_instrs, a_i ↦ₐ w)%I
         r_t1 ↦ᵣ WCap RW b_mem e_mem b_mem
         [[b_mem, e_mem]] ↦ₐ [[ [WInt 0; WInt 0] ]]
r_t2 ↦ᵣ WInt 42
          ( PC ↦ᵣ WCap p_pc b_pc e_pc e_prog
                 r_t1 ↦ᵣ WCap RW b_mem e_mem (b_mem ^+1)%a
                 r_t2 ↦ᵣ WInt 42
                ([∗ list] a_i;w a;prog_instrs, a_i ↦ₐ w)%I
                 [[b_mem, e_mem]] ↦ₐ [[ [WInt 0; WInt 42] ]]
-∗ WP Seq (Instr Executable) {{ φ }}))
       -∗ WP Seq (Instr Executable) {{ φ }}%I.
  Proof.
    intros * Hpc_perm Hpc_bounds Hprog_addr Hmem_bounds.
    iIntros "(HPC& Hprog& Hr1& Hmem& Hr2& Hcont)".
    subst e_mem e_prog; simpl in *.
    (* In order to use the tactic `iCorrectPC` that solve the side-condition
       about the PC, we need this assertion, equivalent to
       `Hpc_perm /\ Hpc_bounds` *)

    assert (Hpc_correct : isCorrectPC_range p_pc b_pc e_pc a_prog (a_prog ^+ 2)%a).
    { unfold isCorrectPC_range. intros.
      apply isCorrectPC_ExecPCPerm_InBounds ; auto ; solve_addr.
    }


    (* Lea *)
    (* Prepare the resources
       Destruct the list of addresses of the code fragment *)

    iDestruct (big_sepL2_length with "Hprog") as %Hlength_prog.
    destruct_list a.
    pose proof (contiguous_between_cons_inv_first _ _ _ _ Hprog_addr) as ->.
    (* Focus to the atomic expression (regarding the operational semantic) *)
    iDestruct "Hprog" as "[Hi Hprog]".
    iApply (wp_bind (fill [SeqCtx])).
    (* Apply the WP rule corresponding to the instruction
       and prove the preconditions of the rule *)

    iApply (wp_lea_success_z with "[$HPC $Hi $Hr1]").
    { apply decode_encode_instrW_inv. }
    { iCorrectPC a_prog (a_prog ^+ 2)%a. }
    { iContiguous_next Hprog_addr 0%nat. }
    { transitivity (Some (b_mem ^+ 1 )%a) ; auto ; solve_addr. }
    { auto. }
    (* Introduce the postconditions of the rule and re-focus the expression. *)
    iNext; iIntros "(HPC& Hdone& Hr1)"; iSimpl.
    iApply wp_pure_step_later;auto;iNext;iIntros "_".

    (* Lea *)
    (* Destruct the list of addresses of the code fragment *)
    pose proof (contiguous_between_last _ _ _ a Hprog_addr eq_refl) as Hlast.

    (* Prepare the memory resource for the Store *)
    iDestruct (region_pointsto_cons with "Hmem") as "(Hmem0& Hmem1)".
    { transitivity (Some (b_mem ^+1)%a) ; auto ; by solve_addr. }
    { by solve_addr. }
    iDestruct (region_pointsto_single with "Hmem1") as "Hmem1".
    { transitivity (Some (b_mem ^+(1+1))%a) ; auto ; by solve_addr. }
    iDestruct "Hmem1" as (v) "(Hmem1& %Hr)".
    injection Hr ; intro Hr' ; subst ; clear Hr.

    (* Focus to the atomic expression (regarding the operational semantic) *)
    iDestruct "Hprog" as "[Hi Hprog]".
    iApply (wp_bind (fill [SeqCtx])).

    (* Apply the WP rule corresponding to the instruction
       and prove the preconditions of the rule *)

    iApply (wp_store_success_reg with "[$HPC $Hi $Hmem1 $Hr2 $Hr1]").
    { apply decode_encode_instrW_inv. }
    { iCorrectPC a_prog (a_prog ^+ 2)%a. }
    { eauto. }
    { eauto. }
    { apply le_addr_withinBounds; solve_addr. }

    (* Introduce the postconditions of the rule and re-focus the expression. *)
    iNext; iIntros "(HPC& Hi& Hr2& Hr1& Hmem1 )"; iSimpl.
    iCombine "Hdone Hi" as "Hdone".
    iApply wp_pure_step_later;auto;iNext ;iIntros "_".

    (* 3 - Continuation *)
    iApply "Hcont".
    iDestruct "Hdone" as "[? ?]".
    iFrame.
    iApply region_pointsto_cons.
    { transitivity (Some (b_mem ^+1)%a) ; auto ; by solve_addr. }
    { by solve_addr. }
    iFrame.
    iApply region_pointsto_cons.
    { transitivity (Some (b_mem ^+(1+1))%a) ; auto ; by solve_addr. }
    { by solve_addr. }
    iFrame.
    replace (b_mem ^+ (1 + 1))%a with (b_mem ^+ 2)%a by solve_addr.
    unfold region_pointsto.
    rewrite finz_seq_between_empty ; last solve_addr.
    done.
  Unshelve. Fail idtac. Admitted.

End base_program.