bedrock.lang.cpp.logic.dispatch
(*
* Copyright (c) 2020 BlueRock Security, Inc.
* This software is distributed under the terms of the BedRock Open-Source License.
* See the LICENSE-BedRock file in the repository root for details.
*)
* Copyright (c) 2020 BlueRock Security, Inc.
* This software is distributed under the terms of the BedRock Open-Source License.
* See the LICENSE-BedRock file in the repository root for details.
*)
Require Import bedrock.lang.proofmode.proofmode.
Require Import bedrock.lang.cpp.syntax.
Require Import bedrock.lang.cpp.semantics.
Require Import bedrock.lang.cpp.logic.pred.
Require Import bedrock.lang.cpp.logic.heap_pred.
Require Import bedrock.lang.cpp.logic.path_pred.
Require Import bedrock.lang.cpp.logic.translation_unit.
Section with_cpp.
Context `{Σ : cpp_logic}.
(* path_names ls extracts the names from ls, failing if any element is not
Tnamed n for some n
NOTE: this is effectively traverse.
*)
Fixpoint path_names (ls : list type) : option (list globname) :=
match ls with
| nil => Some nil
| Tnamed nm :: ls => cons nm <$> path_names ls
| _ => None
end.
Require Import bedrock.lang.cpp.syntax.
Require Import bedrock.lang.cpp.semantics.
Require Import bedrock.lang.cpp.logic.pred.
Require Import bedrock.lang.cpp.logic.heap_pred.
Require Import bedrock.lang.cpp.logic.path_pred.
Require Import bedrock.lang.cpp.logic.translation_unit.
Section with_cpp.
Context `{Σ : cpp_logic}.
(* path_names ls extracts the names from ls, failing if any element is not
Tnamed n for some n
NOTE: this is effectively traverse.
*)
Fixpoint path_names (ls : list type) : option (list globname) :=
match ls with
| nil => Some nil
| Tnamed nm :: ls => cons nm <$> path_names ls
| _ => None
end.
base_to_derived derived path is the offset to derived
from the path path. For example,
Eval simpl in base_to_derived "D" ["B";"A";"X"]%bs.
(* = o_id ,, o_derived σ "X" "A" ,, o_derived σ "A" "B" ,, o_derived σ "B" "D" *)
NOTE the arguments are the same as derived_to_base but the direction
of the cast is swapped.
Eval simpl in base_to_derived "D" ["B";"A";"X"]%bs.
(* = o_id ,, o_derived σ "X" "A" ,, o_derived σ "A" "B" ,, o_derived σ "B" "D" *)
Fixpoint base_to_derived {σ : genv} (derived : globname) (path : list globname) : offset :=
match path with
| nil => o_id
| base :: rest => o_dot (base_to_derived base rest) (o_derived σ base derived)
end.
Definition base_to_derived_ty {σ : genv} (derived : globname) (path : list type) : option offset :=
base_to_derived derived <$> path_names path.
Example _0 : forall {σ: genv},
base_to_derived_ty "D" [Tnamed "C";Tnamed "B";Tnamed "A"] =
Some (o_id ,, _derived "A" "B" ,, _derived "B" "C" ,, _derived "C" "D").
Proof. reflexivity. Succeed Qed. Abort.
match path with
| nil => o_id
| base :: rest => o_dot (base_to_derived base rest) (o_derived σ base derived)
end.
Definition base_to_derived_ty {σ : genv} (derived : globname) (path : list type) : option offset :=
base_to_derived derived <$> path_names path.
Example _0 : forall {σ: genv},
base_to_derived_ty "D" [Tnamed "C";Tnamed "B";Tnamed "A"] =
Some (o_id ,, _derived "A" "B" ,, _derived "B" "C" ,, _derived "C" "D").
Proof. reflexivity. Succeed Qed. Abort.
derived_to_base derived path is the offset from derived
from the path path. For example,
Eval simpl in derived_to_base "::D" ["::B";"::A";"::X"]%bs.
(* = o_base σ "::D" "::B" ,, (o_base σ "::B" "::A" ,, (o_base σ "::A" "::X" ,, o_id)) *)
NOTE the arguments are the same as base_to_derived but the direction
of the cast is swapped.
Eval simpl in derived_to_base "::D" ["::B";"::A";"::X"]%bs.
(* = o_base σ "::D" "::B" ,, (o_base σ "::B" "::A" ,, (o_base σ "::A" "::X" ,, o_id)) *)
Fixpoint derived_to_base {σ : genv} (derived : globname) (path : list globname) : offset :=
match path with
| nil => o_id
| base :: rest => o_dot (o_base σ derived base) (derived_to_base base rest)
end.
Definition derived_to_base_ty {σ : genv} (derived : globname) (path : list type) : option offset :=
derived_to_base derived <$> path_names path.
Example _0 : forall {σ: genv},
derived_to_base_ty "D" [Tnamed "C";Tnamed "B";Tnamed "A"] =
Some (_base "D" "C" ,, (_base "C" "B" ,, (_base "B" "A" ,, o_id))).
Proof. simpl. reflexivity. Succeed Qed. Abort.
match path with
| nil => o_id
| base :: rest => o_dot (o_base σ derived base) (derived_to_base base rest)
end.
Definition derived_to_base_ty {σ : genv} (derived : globname) (path : list type) : option offset :=
derived_to_base derived <$> path_names path.
Example _0 : forall {σ: genv},
derived_to_base_ty "D" [Tnamed "C";Tnamed "B";Tnamed "A"] =
Some (_base "D" "C" ,, (_base "C" "B" ,, (_base "B" "A" ,, o_id))).
Proof. simpl. reflexivity. Succeed Qed. Abort.
If successful, returns a pair of the function pointer to the
implementation and the downcast for this pointer.
Definition get_impl {σ} (base : globname) (path : list globname) (f : obj_name)
: option (ptr * globname * offset) :=
match dispatch.dispatch σ base path f with
| None => None
| Some (cls, path, fptr) => Some (_global fptr, cls, base_to_derived cls path)
end.
Section tu.
Context `{σ : genv}.
Variable tu : translation_unit.
Definition tu_get_impl (base : globname) (path : list globname) (f : obj_name)
: option (ptr * globname * offset) :=
match dispatch.tu_dispatch tu base path f with
| Some (cls, path, fptr) => Some (_global fptr, cls, base_to_derived cls path)
| None => None
end.
Lemma tu_get_impl_ok (MOD : tu ⊧ σ) : forall base path fn a b c,
tu_get_impl base path fn = Some (a, b, c) ->
get_impl base path fn = Some (a, b, c).
Proof.
rewrite /tu_get_impl/get_impl; intros.
do 3 (case_match; try congruence).
erewrite tu_dispatch_ok; eauto.
Qed.
Lemma resolve_match_get_impl (MOD : tu ⊧ σ) {PROP : bi} base path fn a b c (P : _ -> PROP) :
tu_get_impl base path fn = Some (a, b, c) ->
P (a, b, c) -|-
match get_impl base path fn with
| Some x => P x
| None => False
end.
Proof. intros; erewrite tu_get_impl_ok; eauto. Qed.
End tu.
: option (ptr * globname * offset) :=
match dispatch.dispatch σ base path f with
| None => None
| Some (cls, path, fptr) => Some (_global fptr, cls, base_to_derived cls path)
end.
Section tu.
Context `{σ : genv}.
Variable tu : translation_unit.
Definition tu_get_impl (base : globname) (path : list globname) (f : obj_name)
: option (ptr * globname * offset) :=
match dispatch.tu_dispatch tu base path f with
| Some (cls, path, fptr) => Some (_global fptr, cls, base_to_derived cls path)
| None => None
end.
Lemma tu_get_impl_ok (MOD : tu ⊧ σ) : forall base path fn a b c,
tu_get_impl base path fn = Some (a, b, c) ->
get_impl base path fn = Some (a, b, c).
Proof.
rewrite /tu_get_impl/get_impl; intros.
do 3 (case_match; try congruence).
erewrite tu_dispatch_ok; eauto.
Qed.
Lemma resolve_match_get_impl (MOD : tu ⊧ σ) {PROP : bi} base path fn a b c (P : _ -> PROP) :
tu_get_impl base path fn = Some (a, b, c) ->
P (a, b, c) -|-
match get_impl base path fn with
| Some x => P x
| None => False
end.
Proof. intros; erewrite tu_get_impl_ok; eauto. Qed.
End tu.
resolve_virtual σ this cls f Q returns Q fa this' if resolving f on
this results in a function that is equivalent to calling the pointer fa
passing this' as the "this" argument.
TODO: this definition should be changed to use tu_get_impl above.
Definition resolve_virtual
{σ : genv} (this : ptr) (cls : globname) (f : obj_name)
(Q : forall (faddr : ptr) (cls_type : globname) (this_addr : ptr), mpred)
: mpred :=
Exists (path : list globname), (* denoteModule (resolve:=σ) tu ** *)
((Exists q, this |-> derivationR cls path q ** [| path <> nil |] ** True) //\\
match get_impl cls path f with
| Some (fa, cls, off) => Q fa cls (_offset_ptr this off)
| None => (* the function was not found or the implementation was pure virtual *)
False
end).
Lemma resolve_virtual_frame {σ : genv} (cls : globname) (this : ptr) f
(Q Q' : ptr → globname → ptr → mpredI) :
Forall (a : ptr) (b : globname) (c : ptr), Q a b c -* Q' a b c
|-- resolve_virtual this cls f Q -* resolve_virtual this cls f Q'.
Proof.
intros.
rewrite /resolve_virtual.
iIntros "X Y".
iDestruct "Y" as (path) "Y".
iExists path; iFrame.
iSplit.
{ iDestruct "Y" as "[$ _]". }
{ iDestruct "Y" as "[_ Y]". case_match => //.
destruct p as [[??]?]. by iApply "X". }
Qed.
End with_cpp.
{σ : genv} (this : ptr) (cls : globname) (f : obj_name)
(Q : forall (faddr : ptr) (cls_type : globname) (this_addr : ptr), mpred)
: mpred :=
Exists (path : list globname), (* denoteModule (resolve:=σ) tu ** *)
((Exists q, this |-> derivationR cls path q ** [| path <> nil |] ** True) //\\
match get_impl cls path f with
| Some (fa, cls, off) => Q fa cls (_offset_ptr this off)
| None => (* the function was not found or the implementation was pure virtual *)
False
end).
Lemma resolve_virtual_frame {σ : genv} (cls : globname) (this : ptr) f
(Q Q' : ptr → globname → ptr → mpredI) :
Forall (a : ptr) (b : globname) (c : ptr), Q a b c -* Q' a b c
|-- resolve_virtual this cls f Q -* resolve_virtual this cls f Q'.
Proof.
intros.
rewrite /resolve_virtual.
iIntros "X Y".
iDestruct "Y" as (path) "Y".
iExists path; iFrame.
iSplit.
{ iDestruct "Y" as "[$ _]". }
{ iDestruct "Y" as "[_ Y]". case_match => //.
destruct p as [[??]?]. by iApply "X". }
Qed.
End with_cpp.