From 16610f5d6787ed10b284656abdcea905836a32c2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9cile=20RUET-CROS?= <cecile.ruet-cros@cea.fr>
Date: Thu, 12 Dec 2024 10:39:25 +0100
Subject: [PATCH] [wp] replace havoc by memcpy

---
 src/plugins/wp/MemBytes.ml                    | 15 +---
 src/plugins/wp/MemLoader.ml                   | 73 ++++++-------------
 src/plugins/wp/MemLoader.mli                  | 10 +--
 src/plugins/wp/MemMemory.ml                   | 39 +++++-----
 src/plugins/wp/MemMemory.mli                  |  2 +-
 src/plugins/wp/MemRegion.ml                   | 19 ++---
 src/plugins/wp/MemRegion.mli                  |  6 +-
 src/plugins/wp/MemTyped.ml                    | 10 +--
 src/plugins/wp/TacHavoc.ml                    |  8 +-
 .../wp/share/why3/frama_c_wp/memory.mlw       |  6 +-
 10 files changed, 69 insertions(+), 119 deletions(-)

diff --git a/src/plugins/wp/MemBytes.ml b/src/plugins/wp/MemBytes.ml
index da54a47b5d7..30db3c524d2 100644
--- a/src/plugins/wp/MemBytes.ml
+++ b/src/plugins/wp/MemBytes.ml
@@ -49,8 +49,8 @@ struct
   let l_memcpy = Qed.Engine.F_call "memcpy"
   let f_memcpy =
     Lang.extern_f ~library ~typecheck:ty_fst_arg ~link:l_memcpy "memcpy"
-  let memcpy mdst msrc ldst lsrc n =
-    Lang.F.e_fun f_memcpy [mdst;msrc;ldst;lsrc;n]
+  let memcpy mtgt msrc ltgt lsrc length =
+    Lang.F.e_fun f_memcpy [mtgt;msrc;ltgt;lsrc;length]
 
   let p_cinits = Lang.extern_fp ~coloring:true ~library "cinits"
   let cinits m = p_call p_cinits [m]
@@ -674,16 +674,10 @@ module Model = struct
     let n = protected_sizeof_object obj in
     e_sub (e_div (allocated sigma l) n) e_one
 
-  let havoc obj loc ~length chunk ~fresh ~current =
+  let memcpy obj ~mtgt ~msrc ~ltgt ~lsrc ~length chunk =
     if chunk <> Chunk.Alloc then
       let n = e_mul (e_int @@ sizeof_object obj) length in
-      Why3.havoc fresh current loc n
-    else fresh
-
-  let memcpy obj ~lsrc ~ldst ~length chunk ~msrc ~mdst =
-    if chunk <> Chunk.Alloc then
-      let n = e_mul (e_int @@ sizeof_object obj) length in
-      Why3.memcpy mdst msrc ldst lsrc n
+      Why3.memcpy mtgt msrc ltgt lsrc n
     else msrc
 
   let eqmem_forall obj loc _chunk m1 m2 =
@@ -1150,5 +1144,4 @@ let set_init = Model.set_init
 let is_init_range = Model.is_init_range
 let value_footprint = Model.value_footprint
 let init_footprint = Model.init_footprint
-let havoc = Model.havoc
 let memcpy = Model.memcpy
diff --git a/src/plugins/wp/MemLoader.ml b/src/plugins/wp/MemLoader.ml
index b450512c3bf..438544bbf54 100644
--- a/src/plugins/wp/MemLoader.ml
+++ b/src/plugins/wp/MemLoader.ml
@@ -63,10 +63,8 @@ sig
 
   val last : Sigma.t -> c_object -> loc -> term
 
-  val havoc : c_object -> loc -> length:term ->
-    Chunk.t -> fresh:term -> current:term -> term
-  val memcpy : c_object -> lsrc:loc -> ldst:loc -> length:term ->
-    Chunk.t -> msrc:term -> mdst:term -> term
+  val memcpy : c_object -> mtgt:term -> msrc:term -> ltgt:loc -> lsrc:loc ->
+    length:term -> Chunk.t -> term
 
   val eqmem_forall :
     c_object -> loc -> Chunk.t -> term -> term -> var list * pred * pred
@@ -579,60 +577,33 @@ struct
   let () = INIT_LOAD_INFO.load_rec := load_init
 
   (* -------------------------------------------------------------------------- *)
-  (* --- Memcpy                                                             --- *)
+  (* --- Mem Copies \ Havocs                                                --- *)
   (* -------------------------------------------------------------------------- *)
 
-  (*let gen_memcpy_length get_domain s obj ~lsrc ~ldst length =
-    let ps = ref [] in
-    Domain.iter
-      (fun chunk ->
-        let pre  = Sigma.value s.pre  chunk in
-        let post = Sigma.value s.post chunk in
-        let tau = Chunk.tau_of_chunk chunk in
-        let basename = Chunk.basename_of_chunk chunk ^ "_undef" in
-        let mdst = F.e_var (Lang.freshvar ~basename tau) in
-        let havoc = M.memcpy obj ~ldst ~lsrc ~length chunk ~mdst ~msrc:pre in
-        ps := Set(post,havoc) :: !ps
-     ) (get_domain obj ldst) ; !ps
-  *)
-  (* -------------------------------------------------------------------------- *)
-  (* --- Havocs                                                             --- *)
-  (* -------------------------------------------------------------------------- *)
-
-  let gen_havoc_length get_domain s obj loc length =
-(*
-    gen_memcpy_length get_domain s obj ~ldst:loc ~lsrc:loc length
-*)
+  let gen_memcpy_length get_domain s obj ?lsrc loc length =
     let ps = ref [] in
     Domain.iter
       (fun chunk ->
          let pre = Sigma.value s.pre chunk in
          let post = Sigma.value s.post chunk in
          let tau = Chunk.tau_of_chunk chunk in
-         let basename = Chunk.basename_of_chunk chunk ^ "_undef" in
-         let fresh = F.e_var (Lang.freshvar ~basename tau) in
-         let havoc = M.havoc obj loc ~length chunk ~fresh ~current:pre in
-         ps := Set(post,havoc) :: !ps
+         let updated =
+           match lsrc with
+           | None ->
+             let basename = Chunk.basename_of_chunk chunk ^ "_undef" in
+             let fresh = F.e_var (Lang.freshvar ~basename tau) in
+             M.memcpy obj ~mtgt:pre ~msrc:fresh ~ltgt:loc ~lsrc:loc ~length chunk
+           | Some lsrc ->
+             M.memcpy obj ~mtgt:pre ~msrc:pre ~ltgt:loc ~lsrc ~length chunk
+         in ps := Set(post,updated) :: !ps
       ) (get_domain obj loc) ; !ps
 
-  let havoc_length = gen_havoc_length M.value_footprint
-  let havoc seq obj loc = havoc_length seq obj loc F.e_one
+  let memcpy_length = gen_memcpy_length M.value_footprint
+  let memcpy seq obj ?lsrc ltgt = memcpy_length seq obj ltgt ?lsrc F.e_one
 
-  let havoc_init_length = gen_havoc_length M.init_footprint
-  let havoc_init seq obj loc = havoc_init_length seq obj loc F.e_one
-(*
-  let set_init_length s obj loc length =
-    let ps = ref [] in
-    Domain.iter
-      (fun chunk ->
-         let pre = Sigma.value s.pre chunk in
-         let post = Sigma.value s.post chunk in
-         let set = M.set_init obj loc ~length chunk ~current:pre in
-         ps := Set(post,set) :: !ps
-      ) (M.init_footprint obj loc) ; !ps
+  let memcpy_init_length = gen_memcpy_length M.init_footprint
+  let memcpy_init seq obj ?lsrc ltgt = memcpy_init_length seq obj ltgt ?lsrc F.e_one
 
-  let set_init seq obj loc = set_init_length seq obj loc F.e_one
-*)
   (* -------------------------------------------------------------------------- *)
   (* --- Stored & Copied                                                    --- *)
   (* -------------------------------------------------------------------------- *)
@@ -656,14 +627,14 @@ struct
     | C_int _ | C_float _ | C_pointer _ ->
       [ updated_atom seq obj loc value ]
     | C_comp _ | C_array _ ->
-      Set(load_value seq.post obj loc, value) :: havoc seq obj loc
+      Set(load_value seq.post obj loc, value) :: memcpy seq obj loc
 
   let stored_init seq obj loc value =
     match obj with
     | C_int _ | C_float _ | C_pointer _ ->
       [ updated_init_atom seq obj loc value ]
     | C_comp _ | C_array _ ->
-      Set(load_init seq.post obj loc, value) :: havoc_init seq obj loc
+      Set(load_init seq.post obj loc, value) :: memcpy_init seq obj loc
 
   let copied s obj p q = stored s obj p (load_value s.pre obj q)
 
@@ -681,11 +652,11 @@ struct
       [ updated_init_atom seq obj loc (e_var init) ;
         updated_atom seq obj loc (e_var value) ]
     | C_comp _ | C_array _ ->
-      havoc seq obj loc @ havoc_init seq obj loc
+      memcpy seq obj loc @ memcpy_init seq obj loc
 
   let assigned_range s obj l a b =
-    havoc_length s obj (M.shift l obj a) (e_range a b) @
-    havoc_init_length s obj (M.shift l obj a) (e_range a b)
+    memcpy_length s obj (M.shift l obj a) (e_range a b) @
+    memcpy_init_length s obj (M.shift l obj a) (e_range a b)
 
   let assigned seq obj sloc =
     (* Assert (M.monotonic_init seq.pre seq.post) :: *)
diff --git a/src/plugins/wp/MemLoader.mli b/src/plugins/wp/MemLoader.mli
index 3d56fa90c97..18a8b7acf48 100644
--- a/src/plugins/wp/MemLoader.mli
+++ b/src/plugins/wp/MemLoader.mli
@@ -59,10 +59,8 @@ sig
 
   val last : Sigma.t -> c_object -> loc -> term
 
-  val havoc : c_object -> loc -> length:term ->
-    Chunk.t -> fresh:term -> current:term -> term
-  val memcpy : c_object -> lsrc:loc -> ldst:loc -> length:term ->
-    Chunk.t -> msrc:term -> mdst:term -> term
+  val memcpy : c_object -> mtgt:term -> msrc:term -> ltgt:loc -> lsrc:loc ->
+    length:term -> Chunk.t -> term
 
   val eqmem_forall :
     c_object -> loc -> Chunk.t -> term -> term -> var list * pred * pred
@@ -93,8 +91,8 @@ sig
   val load_init : M.Sigma.t -> c_object -> M.loc -> term
   val load_value : M.Sigma.t -> c_object -> M.loc -> term
 
-  val havoc : M.Sigma.t sequence -> c_object -> M.loc -> equation list
-  val havoc_length : M.Sigma.t sequence -> c_object -> M.loc -> term -> equation list
+  val memcpy : M.Sigma.t sequence -> c_object -> ?lsrc:M.loc -> M.loc -> equation list
+  val memcpy_length : M.Sigma.t sequence -> c_object -> ?lsrc:M.loc -> M.loc -> term -> equation list
 
   val stored : M.Sigma.t sequence -> c_object -> M.loc -> term -> equation list
   val stored_init : M.Sigma.t sequence -> c_object -> M.loc -> term -> equation list
diff --git a/src/plugins/wp/MemMemory.ml b/src/plugins/wp/MemMemory.ml
index 1882b4b4fe2..93e0f2287f0 100644
--- a/src/plugins/wp/MemMemory.ml
+++ b/src/plugins/wp/MemMemory.ml
@@ -35,12 +35,12 @@ let ty_fst_arg = function
   | Some l :: _ -> l
   | _ -> raise Not_found
 
-let l_havoc = Qed.Engine.F_call "havoc"
+(* let l_havoc = Qed.Engine.F_call "havoc"*)
 let l_memcpy = Qed.Engine.F_call "memcpy"
 let l_set_init = Qed.Engine.F_call "set_init"
 
 let p_eqmem = Lang.extern_fp ~library "eqmem"
-let f_havoc = Lang.extern_f ~library ~typecheck:ty_fst_arg ~link:l_havoc "havoc"
+(* let f_havoc = Lang.extern_f ~library ~typecheck:ty_fst_arg ~link:l_havoc "havoc" *)
 let f_memcpy = Lang.extern_f ~library ~typecheck:ty_fst_arg ~link:l_memcpy "memcpy"
 let p_framed = Lang.extern_fp ~coloring:true ~library "framed" (* m-pointer -> prop *)
 let p_sconst = Lang.extern_fp ~coloring:true ~library "sconst" (* int-memory -> prop *)
@@ -69,15 +69,18 @@ let framed memory = p_call p_framed [ memory ]
 (* havoc(m_undef, havoc(_undef,m0,p0,a0), p1,a1) =
    - havoc(m_undef, m0, p1,a1) WHEN included (p1,a1,p0,a0) *)
 let r_havoc = function
-  | [undef1;m1;p1;a1] -> begin
-      match F.repr m1 with
-      | L.Fun( f , [_undef0;m0;p0;a0] ) when f == f_havoc -> begin
-          let open Qed.Logic in
-          match MemAddr.is_included [p0;a0;p1;a1] with
-          | Yes -> F.e_fun f_havoc [undef1;m0;p1;a1]
-          | _ -> raise Not_found
-        end
-      | _ -> raise Not_found
+  | [m1;undef1;p1;p2;a1] -> begin
+      if equal p1 p2 then
+        match F.repr m1 with
+        | L.Fun( f , [m0;_undef0;p01;p02;a0] ) when f == f_memcpy ->
+          if equal p01 p02 then begin
+            let open Qed.Logic in
+            match MemAddr.is_included [p01;a0;p1;a1] with
+            | Yes -> F.e_fun f_memcpy [m0;undef1;p1;p2;a1]
+            | _ -> raise Not_found
+          end else raise Not_found
+        | _ -> raise Not_found
+      else raise Not_found
     end
   | _ -> raise Not_found
 
@@ -87,13 +90,13 @@ let r_havoc = function
 *)
 let r_get_havoc es ks =
   match es, ks with
-  | [undef;m;p;a],[k] ->
-    begin
-      match MemAddr.is_separated [p;a;k;e_one] with
+  | [m;undef;p1;p2;a],[k] ->
+    if equal p1 p2 then begin
+      match MemAddr.is_separated [p1;a;k;e_one] with
       | L.Yes -> F.e_get m k
       | L.No  -> F.e_get undef k
       | _ -> raise Not_found
-    end
+    end else raise Not_found
   | _ -> raise Not_found
 
 (* -------------------------------------------------------------------------- *)
@@ -102,8 +105,8 @@ let r_get_havoc es ks =
 
 let () = Context.register
     begin fun () ->
-      F.set_builtin f_havoc r_havoc ;
-      F.set_builtin_get f_havoc r_get_havoc ;
+      F.set_builtin f_memcpy r_havoc ;
+      F.set_builtin_get f_memcpy r_get_havoc ;
     end
 
 (* -------------------------------------------------------------------------- *)
@@ -118,7 +121,7 @@ let frames ~addr:p ~offset:n ~sizeof:s ?(basename="mem") tau =
   let m' = F.e_var (Lang.freshvar ~basename t_mem) in
   let p' = F.e_var (Lang.freshvar ~basename:"q" MemAddr.t_addr) in
   let n' = F.e_var (Lang.freshvar ~basename:"n" L.Int) in
-  let mh = F.e_fun f_havoc [m';m;p';n'] in
+  let mh = F.e_fun f_memcpy [m;m';p';p';n'] in
   let v' = F.e_var (Lang.freshvar ~basename:"v" tau) in
   let meq = F.p_call p_eqmem [m;m';p';n'] in
   let diff = F.p_call MemAddr.p_separated [p;n;p';s] in
diff --git a/src/plugins/wp/MemMemory.mli b/src/plugins/wp/MemMemory.mli
index 3e5cb9ad732..ed0cd5ecd87 100644
--- a/src/plugins/wp/MemMemory.mli
+++ b/src/plugins/wp/MemMemory.mli
@@ -35,7 +35,7 @@ val t_init : tau (** initialization tables *)
 
 val t_mem : tau -> tau (** t_addr indexed array *)
 
-val f_havoc : lfun
+(* val f_havoc : lfun *)
 val f_memcpy : lfun
 val f_set_init : lfun
 
diff --git a/src/plugins/wp/MemRegion.ml b/src/plugins/wp/MemRegion.ml
index 3d33335c0a7..24d8175a3ac 100644
--- a/src/plugins/wp/MemRegion.ml
+++ b/src/plugins/wp/MemRegion.ml
@@ -82,9 +82,8 @@ module type ModelWithLoader = sig
   val last : sigma -> c_object -> loc -> term
   val frames : c_object -> loc -> chunk -> frame list
 
-  val havoc : c_object -> loc -> length:term -> chunk -> fresh:term -> current:term -> term
-  val memcpy : c_object -> lsrc:loc -> ldst:loc -> length:term ->
-    chunk -> msrc:term -> mdst:term -> term
+  val memcpy : c_object -> mtgt:term -> msrc:term -> ltgt:loc -> lsrc:loc ->
+    length:term -> Chunk.t -> term
 
   val eqmem_forall : c_object -> loc -> chunk -> term -> term -> var list * pred * pred
 
@@ -363,23 +362,15 @@ struct
         MemMemory.frames ~addr:(to_addr l) ~offset ~sizeof ~basename tau
       | _ -> []
 
-    let havoc ty l ~length chunk ~fresh ~current =
-      match chunk with
-      | M c -> M.havoc ty (loc l) ~length c ~fresh ~current
-      | R c ->
-        match c.mu with
-        | Value _ | ValInit -> fresh
-        | Array _ | ArrInit -> e_fun f_havoc [fresh;current;to_addr l;length]
-
-    let memcpy ty ~lsrc ~ldst ~length chunk ~msrc ~mdst =
+    let memcpy ty ~mtgt ~msrc ~ltgt ~lsrc ~length chunk =
       match chunk with
       | M c ->
-        M.memcpy ty ~lsrc:(loc lsrc) ~ldst:(loc ldst) ~length c ~msrc ~mdst
+        M.memcpy ty ~mtgt ~msrc ~ltgt:(loc ltgt) ~lsrc:(loc lsrc) ~length c
       | R c ->
         match c.mu with
         | Value _ | ValInit -> msrc
         | Array _ | ArrInit ->
-          e_fun f_memcpy [mdst;msrc;to_addr ldst;to_addr lsrc;length]
+          e_fun f_memcpy [mtgt;msrc;to_addr ltgt;to_addr lsrc;length]
 
     let eqmem_forall ty l chunk m1 m2 =
       match chunk with
diff --git a/src/plugins/wp/MemRegion.mli b/src/plugins/wp/MemRegion.mli
index e35fedf766b..98549024368 100644
--- a/src/plugins/wp/MemRegion.mli
+++ b/src/plugins/wp/MemRegion.mli
@@ -59,10 +59,8 @@ sig
   val last : sigma -> c_object -> loc -> term
   val frames : c_object -> loc -> chunk -> frame list
 
-  val havoc : c_object -> loc -> length:term ->
-    chunk -> fresh:term -> current:term -> term
-  val memcpy : c_object -> lsrc:loc -> ldst:loc -> length:term ->
-    chunk -> msrc:term -> mdst:term -> term
+  val memcpy : c_object -> mtgt:term -> msrc:term -> ltgt:loc -> lsrc:loc ->
+    length:term -> Chunk.t -> term
 
   val eqmem_forall : c_object -> loc -> chunk -> term -> term -> var list * pred * pred
 
diff --git a/src/plugins/wp/MemTyped.ml b/src/plugins/wp/MemTyped.ml
index 146cce9b681..1fb70e45818 100644
--- a/src/plugins/wp/MemTyped.ml
+++ b/src/plugins/wp/MemTyped.ml
@@ -1042,16 +1042,10 @@ struct
     let n = length_of_object obj in
     e_sub (F.e_div (allocated sigma l) n) e_one
 
-  let havoc obj loc ~length chunk ~fresh ~current =
+  let memcpy obj ~mtgt ~msrc ~ltgt ~lsrc ~length chunk =
     if chunk <> T_alloc then
       let n = F.e_mul (length_of_object obj) length in
-      F.e_fun f_havoc [fresh;current;loc;n]
-    else fresh
-
-  let memcpy obj ~lsrc ~ldst ~length chunk ~msrc ~mdst =
-    if chunk <> T_alloc then
-      let n = F.e_mul (length_of_object obj) length in
-      F.e_fun f_memcpy [mdst;msrc;ldst;lsrc;n]
+      F.e_fun f_memcpy [mtgt;msrc;ltgt;lsrc;n]
     else msrc
 
   let eqmem_forall obj loc _chunk m1 m2 =
diff --git a/src/plugins/wp/TacHavoc.ml b/src/plugins/wp/TacHavoc.ml
index ed475f9dae4..840a83a56bd 100644
--- a/src/plugins/wp/TacHavoc.ml
+++ b/src/plugins/wp/TacHavoc.ml
@@ -35,8 +35,10 @@ let lookup_havoc e =
   | L.Aget( m , p ) ->
     begin
       match F.repr m with
-      | L.Fun( f , [m_undef;m_sep;a;n] ) when f == MemMemory.f_havoc ->
-        Some( m_undef , m_sep , a , n , p )
+      | L.Fun( f , [m_sep;m_undef;a;b;n] )
+        when f == MemMemory.f_memcpy ->
+        if F.equal a b then Some( m_sep , m_undef , a , n , p )
+        else None
       | _ -> None
     end
   | _ -> None
@@ -53,7 +55,7 @@ class havoc =
       let e = Tactical.selected sel in
       match lookup_havoc e with
       | None -> Not_applicable
-      | Some(mr,m0,a,n,p) ->
+      | Some(m0,mr,a,n,p) ->
         let separated =
           F.p_call MemAddr.p_separated
             [ p ; F.e_int 1 ; a ; n ] in
diff --git a/src/plugins/wp/share/why3/frama_c_wp/memory.mlw b/src/plugins/wp/share/why3/frama_c_wp/memory.mlw
index f0baf1c96d4..66e83667e96 100644
--- a/src/plugins/wp/share/why3/frama_c_wp/memory.mlw
+++ b/src/plugins/wp/share/why3/frama_c_wp/memory.mlw
@@ -43,10 +43,10 @@ theory Memory
     if separated p 1 b0 s then m0 p else
     let offset = b1.offset - b0.offset + p.offset in
     m1 { b1 with offset = offset }
-
+(*
   function havoc (m0 m1 : map addr 'a) (p:addr) (a:int) : map addr 'a =
     memcpy m1 m0 p p a
-
+*)
   lemma eqmem_included :
     forall m1 m2 : map addr 'a.
     forall p q : addr.
@@ -64,7 +64,7 @@ theory Memory
     forall m0 m1 : map addr 'a.
     forall q p : addr.
     forall a : int.
-    (Map.([]) (havoc m0 m1 p a) (q)) =
+    (Map.([]) (memcpy m1 m0 p p a) (q)) =
       (if (separated q 1 p a) then (Map.([]) (m1) (q)) else (Map.([]) (m0) (q)))
 
   (* Initialization memory *)
-- 
GitLab