Definition meminj_no_overlap (f: meminj) (m: mem) : Prop :=
  forall b1 b1' delta1 b2 b2' delta2 ofs1 ofs2,
  b1 <> b2 ->
  f b1 = Some (b1', delta1) ->
  f b2 = Some (b2', delta2) ->
  perm m b1 ofs1 Max Nonempty ->
  perm m b2 ofs2 Max Nonempty ->
  b1' <> b2' \/ ofs1 + delta1 <> ofs2 + delta2.

(* Specifications: *)
Lemma store_mapped_inj: forall f chunk m1 b1 ofs v1 n1 m2 b2 delta v2, mem_inj f m1 m2 -> store chunk m1 b1 ofs v1 = Some n1 -> meminj_no_overlap f m1 -> f b1 = Some (b2, delta) -> Val.inject f v1 v2 -> exists n2, store chunk m2 b2 (ofs + delta) v2 = Some n2 /\ mem_inj f n1 n2.
Lemma store_unmapped_inj: forall f chunk m1 b1 ofs v1 n1 m2, mem_inj f m1 m2 -> store chunk m1 b1 ofs v1 = Some n1 -> f b1 = None -> mem_inj f n1 m2.
Lemma store_outside_inj: forall f m1 m2 chunk b ofs v m2', mem_inj f m1 m2 -> (forall b' delta ofs', f b' = Some(b, delta) -> perm m1 b' ofs' Cur Readable -> ofs <= ofs' + delta < ofs + size_chunk chunk -> False) -> store chunk m2 b ofs v = Some m2' -> mem_inj f m1 m2'.
Lemma storebytes_mapped_inj: forall f m1 b1 ofs bytes1 n1 m2 b2 delta bytes2, mem_inj f m1 m2 -> storebytes m1 b1 ofs bytes1 = Some n1 -> meminj_no_overlap f m1 -> f b1 = Some (b2, delta) -> list_forall2 (memval_inject f) bytes1 bytes2 -> exists n2, storebytes m2 b2 (ofs + delta) bytes2 = Some n2 /\ mem_inj f n1 n2.
Lemma storebytes_unmapped_inj: forall f m1 b1 ofs bytes1 n1 m2, mem_inj f m1 m2 -> storebytes m1 b1 ofs bytes1 = Some n1 -> f b1 = None -> mem_inj f n1 m2.
Lemma storebytes_outside_inj: forall f m1 m2 b ofs bytes2 m2', mem_inj f m1 m2 -> (forall b' delta ofs', f b' = Some(b, delta) -> perm m1 b' ofs' Cur Readable -> ofs <= ofs' + delta < ofs + Z.of_nat (length bytes2) -> False) -> storebytes m2 b ofs bytes2 = Some m2' -> mem_inj f m1 m2'.
Lemma storebytes_empty_inj: forall f m1 b1 ofs1 m1' m2 b2 ofs2 m2', mem_inj f m1 m2 -> storebytes m1 b1 ofs1 nil = Some m1' -> storebytes m2 b2 ofs2 nil = Some m2' -> mem_inj f m1' m2'.
Lemma alloc_right_inj: forall f m1 m2 lo hi b2 m2', mem_inj f m1 m2 -> alloc m2 lo hi = (m2', b2) -> mem_inj f m1 m2'.
Lemma alloc_left_unmapped_inj: forall f m1 m2 lo hi m1' b1, mem_inj f m1 m2 -> alloc m1 lo hi = (m1', b1) -> f b1 = None -> mem_inj f m1' m2.
Lemma alloc_left_mapped_inj: forall f m1 m2 lo hi m1' b1 b2 delta, mem_inj f m1 m2 -> alloc m1 lo hi = (m1', b1) -> valid_block m2 b2 -> inj_offset_aligned delta (hi-lo) -> (forall ofs k p, lo <= ofs < hi -> perm m2 b2 (ofs + delta) k p) -> f b1 = Some(b2, delta) -> mem_inj f m1' m2.
Lemma free_left_inj: forall f m1 m2 b lo hi m1', mem_inj f m1 m2 -> free m1 b lo hi = Some m1' -> mem_inj f m1' m2.
Lemma free_right_inj: forall f m1 m2 b lo hi m2', mem_inj f m1 m2 -> free m2 b lo hi = Some m2' -> (forall b' delta ofs k p, f b' = Some(b, delta) -> perm m1 b' ofs k p -> lo <= ofs + delta < hi -> False) -> mem_inj f m1 m2'.
Lemma drop_unmapped_inj: forall f m1 m2 b lo hi p m1', mem_inj f m1 m2 -> drop_perm m1 b lo hi p = Some m1' -> f b = None -> mem_inj f m1' m2.
Lemma drop_mapped_inj: forall f m1 m2 b1 b2 delta lo hi p m1', mem_inj f m1 m2 -> drop_perm m1 b1 lo hi p = Some m1' -> meminj_no_overlap f m1 -> f b1 = Some(b2, delta) -> exists m2', drop_perm m2 b2 (lo + delta) (hi + delta) p = Some m2' /\ mem_inj f m1' m2'.
Lemma drop_outside_inj: forall f m1 m2 b lo hi p m2', mem_inj f m1 m2 -> drop_perm m2 b lo hi p = Some m2' -> (forall b' delta ofs' k p, f b' = Some(b, delta) -> perm m1 b' ofs' k p -> lo <= ofs' + delta < hi -> False) -> mem_inj f m1 m2'.
Lemma store_mapped_inj: forall f chunk m1 b1 ofs v1 n1 m2 b2 delta v2, mem_inj f m1 m2 -> store chunk m1 b1 ofs v1 = Some n1 -> meminj_no_overlap f m1 -> f b1 = Some (b2, delta) -> Val.inject f v1 v2 -> exists n2, store chunk m2 b2 (ofs + delta) v2 = Some n2 /\ mem_inj f n1 n2.
Lemma store_unmapped_inj: forall f chunk m1 b1 ofs v1 n1 m2, mem_inj f m1 m2 -> store chunk m1 b1 ofs v1 = Some n1 -> f b1 = None -> mem_inj f n1 m2.
Lemma store_outside_inj: forall f m1 m2 chunk b ofs v m2', mem_inj f m1 m2 -> (forall b' delta ofs', f b' = Some(b, delta) -> perm m1 b' ofs' Cur Readable -> ofs <= ofs' + delta < ofs + size_chunk chunk -> False) -> store chunk m2 b ofs v = Some m2' -> mem_inj f m1 m2'.
Lemma storebytes_mapped_inj: forall f m1 b1 ofs bytes1 n1 m2 b2 delta bytes2, mem_inj f m1 m2 -> storebytes m1 b1 ofs bytes1 = Some n1 -> meminj_no_overlap f m1 -> f b1 = Some (b2, delta) -> list_forall2 (memval_inject f) bytes1 bytes2 -> exists n2, storebytes m2 b2 (ofs + delta) bytes2 = Some n2 /\ mem_inj f n1 n2.
Lemma storebytes_unmapped_inj: forall f m1 b1 ofs bytes1 n1 m2, mem_inj f m1 m2 -> storebytes m1 b1 ofs bytes1 = Some n1 -> f b1 = None -> mem_inj f n1 m2.
Lemma storebytes_outside_inj: forall f m1 m2 b ofs bytes2 m2', mem_inj f m1 m2 -> (forall b' delta ofs', f b' = Some(b, delta) -> perm m1 b' ofs' Cur Readable -> ofs <= ofs' + delta < ofs + Z.of_nat (length bytes2) -> False) -> storebytes m2 b ofs bytes2 = Some m2' -> mem_inj f m1 m2'.
Lemma storebytes_empty_inj: forall f m1 b1 ofs1 m1' m2 b2 ofs2 m2', mem_inj f m1 m2 -> storebytes m1 b1 ofs1 nil = Some m1' -> storebytes m2 b2 ofs2 nil = Some m2' -> mem_inj f m1' m2'.
Lemma alloc_right_inj: forall f m1 m2 lo hi b2 m2', mem_inj f m1 m2 -> alloc m2 lo hi = (m2', b2) -> mem_inj f m1 m2'.
Lemma alloc_left_unmapped_inj: forall f m1 m2 lo hi m1' b1, mem_inj f m1 m2 -> alloc m1 lo hi = (m1', b1) -> f b1 = None -> mem_inj f m1' m2.
Lemma alloc_left_mapped_inj: forall f m1 m2 lo hi m1' b1 b2 delta, mem_inj f m1 m2 -> alloc m1 lo hi = (m1', b1) -> valid_block m2 b2 -> inj_offset_aligned delta (hi-lo) -> (forall ofs k p, lo <= ofs < hi -> perm m2 b2 (ofs + delta) k p) -> f b1 = Some(b2, delta) -> mem_inj f m1' m2.
Lemma free_left_inj: forall f m1 m2 b lo hi m1', mem_inj f m1 m2 -> free m1 b lo hi = Some m1' -> mem_inj f m1' m2.
Lemma free_right_inj: forall f m1 m2 b lo hi m2', mem_inj f m1 m2 -> free m2 b lo hi = Some m2' -> (forall b' delta ofs k p, f b' = Some(b, delta) -> perm m1 b' ofs k p -> lo <= ofs + delta < hi -> False) -> mem_inj f m1 m2'.
Lemma drop_unmapped_inj: forall f m1 m2 b lo hi p m1', mem_inj f m1 m2 -> drop_perm m1 b lo hi p = Some m1' -> f b = None -> mem_inj f m1' m2.
Lemma drop_mapped_inj: forall f m1 m2 b1 b2 delta lo hi p m1', mem_inj f m1 m2 -> drop_perm m1 b1 lo hi p = Some m1' -> meminj_no_overlap f m1 -> f b1 = Some(b2, delta) -> exists m2', drop_perm m2 b2 (lo + delta) (hi + delta) p = Some m2' /\ mem_inj f m1' m2'.
Lemma drop_outside_inj: forall f m1 m2 b lo hi p m2', mem_inj f m1 m2 -> drop_perm m2 b lo hi p = Some m2' -> (forall b' delta ofs' k p, f b' = Some(b, delta) -> perm m1 b' ofs' k p -> lo <= ofs' + delta < hi -> False) -> mem_inj f m1 m2'.