A proof that Flat programs can't detect sound heap re-orderings |
Require
Import
Arith List.
Require
Import
Max.
Require
Import
LambdaTamer.ListUtil.
Require
Import
LambdaTamer.LambdaTamer.
Require
Import
CTPC.AllocMonad.
Require
Import
CTPC.Trace.
Require
Import
CTPC.Dict.
Require
Import
CTPC.Alloc.
Require
Import
CTPC.Flat.
Set Implicit
Arguments.
A characterization of programs with in-bounds slot accesses |
Section
bounded.
Variable
bound : list nat.
Fixpoint
fargs_bounded tp ts (args : fargs tp ts) {struct args} : Prop :=
match args with
| FANil _ => True
| FACons _ _ sl args' => In sl bound /\ fargs_bounded args'
end.
Definition
fprimop_bounded tp t (op : fprimop tp t) : Prop :=
match op with
| FSlot _ sl => In sl bound
| FConst _ _ => True
| FCodeptr _ _ _ => True
| FNew _ _ args => fargs_bounded args
| FProj _ _ sl _ _ => In sl bound
end.
End
bounded.
Fixpoint
flinear_bounded (bound : list nat) tp (lin : flinear tp) {struct lin} : Prop :=
match lin with
| FJump _ args sl _ _ =>
(forall n, n < length args -> In n bound)
/\ In sl bound
| FSet _ sl _ op lin =>
fprimop_bounded bound op
/\ flinear_bounded (sl :: bound) lin
end.
What it means for two heaps to be isomorphic with respect to two roots |
Section
validPath.
Variable
m : mem adom.
Fixpoint
validPath (ptr : nat) (fnums : list nat) {struct fnums} : Prop :=
match fnums with
| nil => True
| fnum :: fnums' =>
match nth_error m ptr with
| None => False
| Some fds =>
match nth_error fds fnum with
| None => True
| Some (Untraced, _) => True
| Some (Traced, ptr') => validPath ptr' fnums'
end
end
end.
End
validPath.
Section
isomorphic_heaps.
Variables
m1 m2 : mem adom.
Fixpoint
followPath (ptr1 ptr2 : nat) (fnums : list nat) {struct fnums} : Prop :=
match fnums with
| nil => True
| fnum :: fnums' =>
match nth_error m1 ptr1, nth_error m2 ptr2 with
| None, None => True
| Some fds1, Some fds2 =>
match nth_error fds1 fnum, nth_error fds2 fnum with
| None, None => True
| Some (Untraced, v1), Some (Untraced, v2) => v1 = v2
| Some (Traced, ptr1'), Some (Traced, ptr2') => followPath ptr1' ptr2' fnums'
| _, _ => False
end
| _, _ => False
end
end.
Definition
isomorphic_pointers (ptr1 ptr2 : nat) :=
forall fnums, validPath m1 ptr1 fnums
/\ validPath m2 ptr2 fnums
/\ followPath ptr1 ptr2 fnums.
Definition
isomorphic_values (t : aty) (v1 v2 : nat) : Prop :=
match t with
| ARef => isomorphic_pointers v1 v2
| _ => v1 = v2
end.
Definition
isomorphic_slots (bound : list nat) (tp : ftyping) (sls1 sls2 : slots) : Prop :=
forall n, In n bound
-> isomorphic_values (NatDict.sel tp n)
(NatDict.sel sls1 n) (NatDict.sel sls2 n).
Theorem
isomorphic_slots_mono : forall (bound1 : list nat) (tp : ftyping) (sls1 sls2 : slots),
isomorphic_slots bound1 tp sls1 sls2
-> forall bound2, incl bound2 bound1
-> isomorphic_slots bound2 tp sls1 sls2.
Definition
isomorphic_args (ts : atys) (args1 args2 : list adom) : Prop :=
forall n,
match nth_error ts n with
| None =>
match nth_error args1 n, nth_error args2 n with
| None, None => True
| _, _ => False
end
| Some t =>
match nth_error args1 n, nth_error args2 n with
| Some (tg1, arg1), Some (tg2, arg2) =>
tg1 = tagof t /\ tg2 = tagof t
/\ isomorphic_values t arg1 arg2
| _, _ => False
end
end.
Theorem
fargs_safe : forall bound (sls1 sls2 : slots) tp ts (e : fargs tp ts),
isomorphic_slots bound tp sls1 sls2
-> fargs_bounded bound e
-> isomorphic_args ts (fargsDenote e sls1) (fargsDenote e sls2).
End
isomorphic_heaps.
Hint
Resolve nth_error_monotone.
Ltac
caseEq e := generalize (refl_equal e); pattern e at -1; case e.
Theorem
validPath_monotone : forall m fnums v,
validPath m v fnums
-> forall m',
validPath (m ++ m') v fnums.
Hint
Resolve validPath_monotone.
Theorem
followPath_monotone : forall m1 m2 fnums v1 v2,
validPath m1 v1 fnums
-> validPath m2 v2 fnums
-> followPath m1 m2 v1 v2 fnums
-> forall m1' m2',
followPath (m1 ++ m1') (m2 ++ m2') v1 v2 fnums.
Hint
Resolve followPath_monotone.
Theorem
isomorphic_pointers_monotone : forall m1 m2 v1 v2,
isomorphic_pointers m1 m2 v1 v2
-> forall m1' m2',
isomorphic_pointers (m1 ++ m1') (m2 ++ m2') v1 v2.
Hint
Resolve isomorphic_pointers_monotone.
Theorem
isomorphic_values_monotone : forall m1 m2 t v1 v2,
isomorphic_values m1 m2 t v1 v2
-> forall m1' m2',
isomorphic_values (m1 ++ m1') (m2 ++ m2') t v1 v2.
Hint
Resolve isomorphic_values_monotone.
Theorem
isomorphic_slots_monotone : forall bound m1 m2 tp sls1 sls2,
isomorphic_slots m1 m2 bound tp sls1 sls2
-> forall m1' m2',
isomorphic_slots (m1 ++ m1') (m2 ++ m2') bound tp sls1 sls2.
Hint
Resolve isomorphic_slots_monotone.
More safety results |
Lemma
isomorphic_new : forall m1 m2 ts args1 args2,
isomorphic_args m1 m2 ts args1 args2
-> isomorphic_pointers (m1 ++ args1 :: nil) (m2 ++ args2 :: nil)
(length m1) (length m2).
Hint
Resolve isomorphic_new fargs_safe.
Ltac
rewriter :=
repeat match goal with
| [ H : _ |- _ ] => rewrite H
end.
Theorem
fprimop_safe : forall tp t (op : fprimop tp t)
(m1 m2 : mem adom) bound (sls1 sls2 : slots),
isomorphic_slots m1 m2 bound tp sls1 sls2
-> fprimop_bounded bound op
-> match fprimopDenote op sls1 m1, fprimopDenote op sls2 m2 with
| None, None => True
| Some (m1', v1), Some (m2', v2) =>
isomorphic_slots m1' m2' bound tp sls1 sls2
/\ isomorphic_values m1' m2' t v1 v2
| _, _ => False
end.
Fixpoint
init_bound (n : nat) : list nat :=
match n with
| O => nil
| S n' => n' :: init_bound n'
end.
Theorem
init_bound_incl : forall m bound,
(forall n, n < m -> In n bound)
-> incl (init_bound m) bound.
Hint
Resolve init_bound_incl.
Theorem
flinear_safe : forall tp (lin : flinear tp)
(m1 m2 : mem adom) bound (sls1 sls2 : slots),
isomorphic_slots m1 m2 bound tp sls1 sls2
-> flinear_bounded bound lin
-> match flinearDenote lin sls1 m1, flinearDenote lin sls2 m2 with
| None, None => True
| Some (m1', (pc1, argsT1, sls'1)), Some (m2', (pc2, argsT2, sls'2)) =>
exists tp',
isomorphic_slots m1' m2' (init_bound (length argsT1)) tp' sls'1 sls'2
/\ pc1 = pc2
/\ argsT1 = argsT2
/\ fprecondition tp' argsT1
| _, _ => False
end.
Lemma
flatContext_sel'' : forall argsT t argsT',
NatDict.sel (flatContext (argsT ++ t :: argsT')) (length argsT') = t.
Lemma
flatContext_sel' : forall argsT t argsT',
NatDict.sel (flatContext (argsT +++ t :: argsT')) (length argsT') = t.
Theorem
flatContext_sel : forall argsT argsT' n t,
nth_error argsT n = Some t
-> NatDict.sel (flatContext (argsT +++ argsT')) (length argsT' + n) = t.
Theorem
nth_error_total : forall (argsT : list aty) n,
n < length argsT
-> exists t, nth_error argsT n = Some t.
Theorem
In_init_bound : forall m n,
In n (init_bound m)
-> n < m.
Theorem
precondition_safe : forall tp argsT m1 m2 sls1 sls2,
fprecondition tp argsT
-> isomorphic_slots m1 m2 (init_bound (length argsT)) tp sls1 sls2
-> isomorphic_slots m1 m2 (init_bound (length argsT)) (flatContext (argsT +++ nil)) sls1 sls2.
Theorem
flatContext_inj : forall ts1 ts2,
flatContext ts1 = flatContext ts2
-> ts1 = ts2.
Theorem
revApp_inj : forall (ls1 : list aty) ls2 ls'1 ls'2,
ls1 +++ ls'1 = ls2 +++ ls'2
-> length ls'1 = length ls'2
-> ls1 = ls2 /\ ls'1 = ls'2.
Theorem
flatContext_revApp_inj : forall ts1 ts2,
flatContext (ts1 +++ nil) = flatContext (ts2 +++ nil)
-> ts1 = ts2.
Section
Traces.
Variable
G : ftyping.
Variable
pr : fprog G.
Hypothesis
funcs_bounded : forall pc sg,
nthI (fFuncs pr) pc = Some sg
-> exists argsT, projS1 sg = flatContext (argsT +++ nil)
/\ flinear_bounded (init_bound (length argsT)) (projS2 sg).
Theorem
ftrace_safe' : forall tr output,
runTrace tr output
-> forall (m1 m2 : mem adom)
pc argsT (sls1 sls2 : slots) tp,
fprecondition tp argsT
-> isomorphic_slots m1 m2 (init_bound (length argsT)) tp sls1 sls2
-> tr = fmakeTrace pr m1 pc argsT sls1
-> fmakeTrace pr m1 pc argsT sls1 = fmakeTrace pr m2 pc argsT sls2.
Theorem
ftrace_safe : forall (m1 m2 : mem adom)
pc argsT (sls1 sls2 : slots) tp,
fprecondition tp argsT
-> isomorphic_slots m1 m2 (init_bound (length argsT)) tp sls1 sls2
-> forall output,
runTrace (fmakeTrace pr m1 pc argsT sls1) output
-> fmakeTrace pr m1 pc argsT sls1 = fmakeTrace pr m2 pc argsT sls2.
Hypothesis
body_bounded : exists argsT, G = flatContext (argsT +++ nil)
/\ flinear_bounded (init_bound (length argsT)) (fBody pr).
Theorem
fprog_safe : forall argsT,
G = flatContext (argsT +++ nil)
-> (forall argsT', G = flatContext (argsT' +++ nil)
-> flinear_bounded (init_bound (length argsT')) (fBody pr))
-> forall m1 m2 sls1 sls2,
isomorphic_slots m1 m2 (init_bound (length argsT)) G sls1 sls2
-> forall output, runTrace (fprogDenote pr sls1 m1) output
-> fprogDenote pr sls1 m1 = fprogDenote pr sls2 m2.
End
Traces.
Prove that Flatify generates well-bounded programs |
Require
Import
Eqdep.
Require
Import
CTPC.Flatify.
Theorem
flatVar_bounded : forall G t (v : Var G t),
In (flatVar v) (init_bound (length G)).
Hint
Resolve flatVar_bounded.
Theorem
flatArgs_bounded : forall G ts (args : aargs G ts),
fargs_bounded (init_bound (length G)) (flatArgs args).
Hint
Resolve flatArgs_bounded.
Theorem
flatPrimop_bounded : forall G t (op : aprimop G t),
fprimop_bounded (init_bound (length G)) (flatPrimop op).
Hint
Resolve flatPrimop_bounded.
Fixpoint
stash_bound (ts : list aty) (start : nat) (bound : list nat) {struct ts} : list nat :=
match ts with
| nil => bound
| t :: ts' => start :: stash_bound ts' (S start) bound
end.
Theorem
stash_bound_mono : forall (ts : list aty) (start : nat) (bound : list nat),
incl bound (stash_bound ts start bound).
Theorem
stash_bounded : forall (tp : ftyping) (ts : list aty) (args : fargs tp ts) (start : nat)
(Hearly : args_early args start) (lin : flinear (stashType tp start ts)) bound,
flinear_bounded (stash_bound ts start bound) lin
-> fargs_bounded bound args
-> flinear_bounded bound (stash args _ Hearly lin).
Hint
Resolve stash_bounded.
Fixpoint
copy_bound (to from len : nat) (bound : list nat) {struct len} : list nat :=
match len with
| O => bound
| S len' => to :: copy_bound (S to) (S from) len' bound
end.
Theorem
copy_bound_mono : forall (len to from : nat) (bound : list nat),
incl bound (copy_bound to from len bound).
Theorem
copy_bounded : forall (len : nat) (tp : ftyping) (to from : nat)
(lin : flinear (copyType tp to from len)) bound,
(forall n, from <= n < from + len -> In n bound)
-> flinear_bounded (copy_bound to from len bound) lin
-> flinear_bounded bound (copy tp to from len lin).
Theorem
stash_bound_has : forall (ts : list aty) (start : nat) (bound : list nat) n,
start <= n < start + length ts
-> In n (stash_bound ts start bound).
Hint
Resolve stash_bound_has.
Theorem
copy_bound_has : forall (len to from : nat) (bound : list nat) n,
to <= n < to + len
-> In n (copy_bound to from len bound).
Hint
Resolve copy_bound_has.
Theorem
frob_args_bounded : forall tp ts (args : fargs tp ts) a t
(Hearly : args_early args a) bound,
fargs_bounded bound args
-> fargs_bounded bound (frob_args args a t Hearly).
Hint
Resolve frob_args_bounded.
Theorem
fargs_bounded_mono : forall tp ts (args : fargs tp ts) bound,
fargs_bounded bound args
-> forall bound', fargs_bounded (bound' ++ bound) args.
Hint
Resolve fargs_bounded_mono.
Theorem
fargs_bounded_mono' : forall tp ts (args : fargs tp ts) bound,
fargs_bounded bound args
-> forall bound', fargs_bounded (bound' :: bound) args.
Hint
Resolve fargs_bounded_mono'.
Theorem
flatLinear_bounded : forall G t (lin : alinear G t),
flinear_bounded (init_bound (length G)) (flatLinear lin).
Hint
Resolve flatLinear_bounded.
Theorem
flatFunc_bounded : forall G ts (f : afunc G ts),
flinear_bounded (init_bound (length (ts +++ G))) (flatFunc f).
Hint
Resolve flatFunc_bounded.
Section
mapI.
Variable
A : Set.
Variable
B : A -> Set.
Variable
A' : Set.
Variable
f : A -> A'.
Variable
B' : A' -> Set.
Variable
g : forall x, B x -> B' (f x).
Theorem
nthI_mapI' : forall (ts : list A) (ls : listI B ts) n sg,
nthI (A:= A') (mapI g ls) n = value sg
-> exists v, nthI ls n = value v
/\ projS1 sg = f (projS1 v)
/\ forall (Heq : projS1 sg = f (projS1 v)),
eq_rec _ _ (projS2 sg) _ Heq = g (projS2 v).
End
mapI.
Theorem
flatProg_funcs_bounded : forall (G : list aty) (pr : aprog G) pc sg,
nthI (fFuncs (flatProg pr)) pc = Some sg
-> exists argsT, projS1 sg = flatContext (argsT +++ nil)
/\ flinear_bounded (init_bound (length argsT)) (projS2 sg).
Theorem
flatProg_body_bounded : forall (G : list aty) (pr : aprog G),
exists argsT, flatContext (G +++ nil) = flatContext (argsT +++ nil)
/\ flinear_bounded (init_bound (length argsT)) (fBody (flatProg pr)).