From db7526e879f480adc0d7b29e7c781340c2b5e7e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Fri, 5 Mar 2021 14:56:03 +0100
Subject: [PATCH] [Eva] Fixes the cvalue domain on recursive calls.

---
 .../value/domains/cvalue/cvalue_domain.ml     | 51 ++++++++-----------
 .../value/domains/cvalue/locals_scoping.ml    | 13 +++--
 .../value/domains/cvalue/locals_scoping.mli   |  5 +-
 3 files changed, 31 insertions(+), 38 deletions(-)

diff --git a/src/plugins/value/domains/cvalue/cvalue_domain.ml b/src/plugins/value/domains/cvalue/cvalue_domain.ml
index aa7f27b0021..e31a140be37 100644
--- a/src/plugins/value/domains/cvalue/cvalue_domain.ml
+++ b/src/plugins/value/domains/cvalue/cvalue_domain.ml
@@ -230,21 +230,19 @@ module State = struct
     Cvalue_transfer.assume stmt expr positive valuation s >>-: fun s ->
     s, clob
 
+  let is_direct_recursion stmt call =
+    try
+      let kf = Kernel_function.find_englobing_kf stmt in
+      Kernel_function.equal kf call.kf
+    with Not_found -> false (* Should not happen *)
+
   let start_recursive_call stmt call recursion (state, clob) =
-    let direct =
-      try
-        let kf = Kernel_function.find_englobing_kf stmt in
-        Kernel_function.equal kf call.kf
-      with Not_found -> false (* Should not happen *)
-    in
+    let direct = is_direct_recursion stmt call in
     let state = Model.remove_variables recursion.withdrawal state in
-    let state = Model.replace_base recursion.base_substitution state in
+    let substitution = recursion.base_substitution in
     let clob = if direct then clob else Locals_scoping.top () in
-    let state, set =
-      Locals_scoping.substitute recursion.base_substitution clob state
-    in
-    Locals_scoping.remember_bases_with_locals clob (Base.SetLattice.inject set);
-    state
+    let state = Locals_scoping.substitute substitution clob state in
+    Model.replace_base substitution state
 
   let start_call stmt call recursion valuation (state, clob) =
     let state =
@@ -256,31 +254,26 @@ module State = struct
     >>-: fun state -> state, Locals_scoping.bottom ()
 
   let finalize_recursive_call stmt call ~pre recursion state =
-    let direct =
-      try
-        let kf = Kernel_function.find_englobing_kf stmt in
-        Kernel_function.equal kf call.kf
-      with Not_found -> false (* Should not happen *)
-    in
+    let direct = is_direct_recursion stmt call in
     let pre, clob = pre in
+    let substitution = recursion.base_substitution in
+    let state = Model.replace_base substitution state in
+    let clob = if direct then clob else Locals_scoping.top () in
+    let state = Locals_scoping.substitute substitution clob state in
     let shape = Base.Hptset.shape recursion.base_withdrawal in
     let inter = Cvalue.Model.filter_by_shape shape pre in
-    let state = Cvalue.Model.merge ~into:state inter in
-    let state = Model.replace_base recursion.base_substitution state in
-    let clob = if direct then clob else Locals_scoping.top () in
-    let state, _set =
-      Locals_scoping.substitute recursion.base_substitution clob state
-    in
-    state
+    Cvalue.Model.merge ~into:state inter
 
   let finalize_call stmt call recursion ~pre ~post =
+    let (pre, clob) = pre in
     let (post, post_clob) = post in
+    Locals_scoping.(remember_bases_with_locals clob post_clob.clob);
     let post =
-      Extlib.opt_fold (finalize_recursive_call stmt call ~pre) recursion post
+      Extlib.opt_fold
+        (finalize_recursive_call stmt call ~pre:(pre, clob))
+        recursion post
     in
-    let (pre, clob) = pre in
-    Locals_scoping.(remember_bases_with_locals clob post_clob.clob);
-    Cvalue_transfer.finalize_call stmt call recursion  ~pre ~post
+    Cvalue_transfer.finalize_call stmt call recursion ~pre ~post
     >>-: fun state ->
     state, clob
 
diff --git a/src/plugins/value/domains/cvalue/locals_scoping.ml b/src/plugins/value/domains/cvalue/locals_scoping.ml
index d8eea04d82b..9fc5b4d5dee 100644
--- a/src/plugins/value/domains/cvalue/locals_scoping.ml
+++ b/src/plugins/value/domains/cvalue/locals_scoping.ml
@@ -130,12 +130,12 @@ let make_escaping_fundec fundec clob vars state =
 let substitute substitution clob state =
   (* Apply the [substitution] to [offsm]. If it is modified, bind the new
      offsetmap to [base] in [state], and add the [base] to [set]. *)
-  let replace_offsm base offsm (state, set) =
+  let replace_offsm base offsm state =
     let f v = snd (Cvalue.V_Or_Uninitialized.replace_base substitution v) in
     let offsm' = Cvalue.V_Offsetmap.map_on_values f offsm in
     if Cvalue.V_Offsetmap.equal offsm' offsm
-    then state, set
-    else Cvalue.Model.add_base base offsm' state, Base.Hptset.add base set
+    then state
+    else Cvalue.Model.add_base base offsm' state
   in
   (* Apply the substitution to the offsetmap bound to [base] in [state] *)
   let replace_base base acc =
@@ -144,15 +144,14 @@ let substitute substitution clob state =
     | `Top | `Bottom -> acc
     | exception Not_found -> acc
   in
-  let acc = state, Base.Hptset.empty in
   (* Iterate on all the bases that might contain a variable to substitute *)
-  try Base.SetLattice.fold replace_base clob.clob (replace_base Base.null acc)
+  try Base.SetLattice.fold replace_base clob.clob (replace_base Base.null state)
   with Abstract_interp.Error_Top ->
   (* [clob] is too imprecise. Iterate on the entire memory state instead,
      which is much slower. *)
   match state with
-  | Cvalue.Model.Top | Cvalue.Model.Bottom -> acc
-  | Cvalue.Model.Map map -> Cvalue.Model.fold replace_offsm map acc
+  | Cvalue.Model.Top | Cvalue.Model.Bottom -> state
+  | Cvalue.Model.Map map -> Cvalue.Model.fold replace_offsm map state
 
 (*
 Local Variables:
diff --git a/src/plugins/value/domains/cvalue/locals_scoping.mli b/src/plugins/value/domains/cvalue/locals_scoping.mli
index 9da04c27dad..64cdf339a39 100644
--- a/src/plugins/value/domains/cvalue/locals_scoping.mli
+++ b/src/plugins/value/domains/cvalue/locals_scoping.mli
@@ -71,8 +71,9 @@ val make_escaping_fundec:
     function, in which case a different warning is emitted. *)
 
 val substitute:
-  Base.substitution -> clobbered_set -> Cvalue.Model.t ->
-  Cvalue.Model.t * Base.Hptset.t
+  Base.substitution -> clobbered_set -> Cvalue.Model.t -> Cvalue.Model.t
+(** [substitute substitution clob state] applies [substitution] to all pointer
+    values in the offsetmaps bound to variables in [clob] in [state]. *)
 
 (*
 Local Variables:
-- 
GitLab