(** The values of the erased memory may be more defined and its
       permissions are top.*)
  (** In retrospect setting the permissions to top was a bad
  choice. It should have been that the permissions of the erased
  memory are above the permissions of the other memory. This would
  make it more reusable and it wouldn't need a second definition for
  free. *)

  Local Notation "a # b" := (PMap.get b a) (at level 1).

(* Specifications: *)
Lemma mem_erasure_restr: forall m m' pmap (Hlt: permMapLt pmap (getMaxPerm m)), mem_erasure m m' -> mem_erasure (restrPermMap Hlt) m'.
Lemma mem_erasure_dilute_1: forall m m', mem_erasure m m' -> mem_erasure (setMaxPerm m) m'.
Lemma proj_bytes_erasure: forall vl vl', memval_erasure_list vl vl' -> forall bl, proj_bytes vl = Some bl -> proj_bytes vl' = Some bl.
Lemma proj_bytes_not_erasure: forall vl vl', memval_erasure_list vl vl' -> proj_bytes vl = None -> proj_bytes vl' <> None -> In Undef vl.
Lemma check_value_erasure: forall vl vl', memval_erasure_list vl vl' -> forall v v' q n, check_value n v q vl = true -> val_erasure v v' -> v <> Vundef -> check_value n v' q vl' = true.
Lemma proj_value_erasure: forall q vl1 vl2, memval_erasure_list vl1 vl2 -> val_erasure (proj_value q vl1) (proj_value q vl2).
Lemma load_result_erasure: forall chunk v1 v2, val_erasure v1 v2 -> val_erasure (Val.load_result chunk v1) (Val.load_result chunk v2).
Lemma decode_val_erasure: forall vl1 vl2 chunk, memval_erasure_list vl1 vl2 -> val_erasure (decode_val chunk vl1) (decode_val chunk vl2).
Lemma mem_load_erased: forall chunk m m' b ofs v (Hload: Mem.load chunk m b ofs = Some v) (Herased: mem_erasure m m'), exists v', Mem.load chunk m' b ofs = Some v' /\ val_erasure v v'.
Lemma setN_erasure : forall (vl1 vl2 : seq.seq memval), memval_erasure_list vl1 vl2 -> forall (p : Z) (c1 c2 : ZMap.t memval), (forall q : Z, memval_erasure (ZMap.get q c1) (ZMap.get q c2)) -> forall q : Z, memval_erasure (ZMap.get q (Mem.setN vl1 p c1)) (ZMap.get q (Mem.setN vl2 p c2)).
Lemma mem_store_erased: forall chunk m m' b ofs v v' m2 (Hstore: Mem.store chunk m b ofs v = Some m2) (Herased: mem_erasure m m') (Hval_erasure: val_erasure v v') , exists m2', Mem.store chunk m' b ofs v' = Some m2' /\ mem_erasure m2 m2'.
Lemma mem_loadv_erased: forall chunk m m' vptr v (Hload: Mem.loadv chunk m vptr = Some v) (Herased: mem_erasure m m'), exists v', Mem.loadv chunk m' vptr = Some v' /\ val_erasure v v'.
Lemma mem_storev_erased: forall chunk m m' vptr v v' m2 (Hstore: Mem.storev chunk m vptr v = Some m2) (Herased: mem_erasure m m') (Hval_erasure: val_erasure v v') , exists m2', Mem.storev chunk m' vptr v' = Some m2' /\ mem_erasure m2 m2'.
Lemma mem_erasure_valid_pointer: forall m m' b ofs, mem_erasure m m' -> Mem.valid_pointer m b ofs -> Mem.valid_pointer m' b ofs.
Lemma mem_erasure_valid_pointer_guard: forall m m' b ofs ofs', mem_erasure m m' -> Mem.valid_pointer m' b ofs || Mem.valid_pointer m' b ofs' = false -> Mem.valid_pointer m b ofs || Mem.valid_pointer m b ofs'= false.
Lemma val_erasure_cmpu: forall v1 v2 v1' v2' m m' cmp (Hval_erasure: val_erasure v1 v1') (Hval_erasure2: val_erasure v2 v2') (Hmem: mem_erasure m m'), val_erasure (Val.cmpu (Mem.valid_pointer m) cmp v1 v2) (Val.cmpu (Mem.valid_pointer m') cmp v1' v2').
Lemma val_erasure_cmplu: forall v1 v2 v1' v2' m m' cmp (Hval_erasure: val_erasure v1 v1') (Hval_erasure2: val_erasure v2 v2') (Hmem: mem_erasure m m'), val_erasure (Val.maketotal (Val.cmplu (Mem.valid_pointer m) cmp v1 v2)) (Val.maketotal (Val.cmplu (Mem.valid_pointer m') cmp v1' v2')).
Lemma storev_pointer: forall chunk m vptr v m', Mem.storev chunk m vptr v = Some m' -> isPointer vptr.
Lemma loadv_pointer: forall chunk m vptr v, Mem.loadv chunk m vptr = Some v -> isPointer vptr.
Lemma memval_erasure_list_length: forall mv mv', memval_erasure_list mv mv' -> length mv = length mv'.
Lemma storebytes_erasure: forall m m' b ofs mv mv' m2 (Hstore: Mem.storebytes m b ofs mv = Some m2) (Herased: mem_erasure m m') (Hval_erasure: memval_erasure_list mv mv') , exists m2', Mem.storebytes m' b ofs mv' = Some m2' /\ mem_erasure m2 m2'.
Lemma loadbytes_erasure: forall m m' b ofs sz bytes (Hmem_erasure: mem_erasure m m') (Hloadbytes: Mem.loadbytes m b ofs sz = Some bytes), exists bytes', Mem.loadbytes m' b ofs sz = Some bytes' /\ memval_erasure_list bytes bytes'.
Lemma mem_erasure_idempotent: forall m m', mem_erasure m m' -> mem_erasure m (erasePerm m').
Lemma mem_erasure'_erase: forall m m', mem_erasure' m m' -> mem_erasure m (erasePerm m').
Lemma alloc_erasure': forall m m' lo hi m2 m2' b b' (Herased: mem_erasure m m') (Halloc: Mem.alloc m lo hi = (m2, b)) (Halloc': Mem.alloc m' lo hi = (m2', b')), mem_erasure' m2 m2' /\ b = b'.
Lemma mem_free_erasure': forall m m' lo hi m2 b (Herased: mem_erasure m m') (Hfree: Mem.free m b lo hi = Some m2), exists m2', Mem.free m' b lo hi = Some m2' /\ mem_erasure' m2 m2'.
Lemma mem_store_erased': forall chunk m m' b ofs v v' m2 (Hstore: Mem.store chunk m b ofs v = Some m2) (Herased: mem_erasure' m m') (Hval_erasure: val_erasure v v') , exists m2', Mem.store chunk m' b ofs v' = Some m2' /\ mem_erasure' m2 m2'.
Lemma mem_storev_erased': forall chunk m m' vptr v v' m2 (Hstore: Mem.storev chunk m vptr v = Some m2) (Herased: mem_erasure' m m') (Hval_erasure: val_erasure v v') , exists m2', Mem.storev chunk m' vptr v' = Some m2' /\ mem_erasure' m2 m2'.
Lemma mem_loadv_erased' : forall (chunk : memory_chunk) (m m' : mem) (vptr v : val) (Hload: Mem.loadv chunk m vptr = Some v) (Herased: mem_erasure' m m'), exists v' : val, Mem.loadv chunk m' vptr = Some v' /\ val_erasure v v'.
Lemma mem_erasure_erasure': forall m m', mem_erasure m m' -> mem_erasure' m m'.