From e711d912b7800e25e0e8bb28e9fc693be1c6740e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Tue, 22 Feb 2022 09:43:12 +0100
Subject: [PATCH] [Eva] Implements [use_spec_instead_of_definition] in
 function_calls.

Must be consistent with [define_analysis_target].
---
 Makefile                                    |  4 ++--
 src/plugins/value/engine/function_calls.ml  |  8 ++++++++
 src/plugins/value/engine/function_calls.mli |  5 +++++
 src/plugins/value/engine/transfer_logic.ml  |  2 +-
 src/plugins/value/engine/transfer_stmt.ml   |  2 +-
 src/plugins/value/gui_files/gui_eval.ml     |  5 +++--
 src/plugins/value/legacy/eval_annots.ml     |  2 +-
 src/plugins/value/register.ml               | 11 ++---------
 8 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/Makefile b/Makefile
index 531ba1bf1fa..8a1d9897659 100644
--- a/Makefile
+++ b/Makefile
@@ -899,7 +899,7 @@ PLUGIN_CMO:= partitioning/split_strategy domains/domain_mode self parameters \
 	domains/cvalue/builtins_watchpoint \
 	domains/cvalue/builtins_float domains/cvalue/builtins_split \
 	domains/inout_domain \
-	legacy/eval_terms legacy/eval_annots \
+	legacy/eval_terms \
 	domains/cvalue/cvalue_transfer domains/cvalue/cvalue_init \
 	domains/cvalue/cvalue_specification \
 	domains/cvalue/cvalue_domain \
@@ -908,7 +908,7 @@ PLUGIN_CMO:= partitioning/split_strategy domains/domain_mode self parameters \
 	partitioning/auto_loop_unroll \
 	partitioning/partition partitioning/partitioning_parameters \
 	partitioning/partitioning_index partitioning/trace_partitioning \
-	engine/recursion engine/function_calls \
+	engine/recursion engine/function_calls legacy/eval_annots \
 	engine/subdivided_evaluation engine/evaluation engine/abstractions \
 	engine/transfer_logic engine/transfer_stmt engine/transfer_specification \
 	engine/mem_exec engine/iterator engine/initialization \
diff --git a/src/plugins/value/engine/function_calls.ml b/src/plugins/value/engine/function_calls.ml
index eff7dbc77a5..7c368ffcbae 100644
--- a/src/plugins/value/engine/function_calls.ml
+++ b/src/plugins/value/engine/function_calls.ml
@@ -123,6 +123,14 @@ let analysis_status kf =
   with Not_found -> Unreachable
 
 
+(* Must be consistent with the choice made by [analysis_target] below. *)
+let use_spec_instead_of_definition ?(recursion_depth = -1) kf =
+  Ast_info.is_frama_c_builtin (Kernel_function.get_name kf) ||
+  Builtins.is_builtin_overridden kf ||
+  recursion_depth >= Parameters.RecursiveUnroll.get () ||
+  not (Kernel_function.is_definition kf) ||
+  Kernel_function.Set.mem kf (Parameters.UsePrototype.get ())
+
 let analysis_target ~recursion_depth callsite kf =
   match Builtins.find_builtin_override kf with
   | Some (name, builtin, cache, spec) ->
diff --git a/src/plugins/value/engine/function_calls.mli b/src/plugins/value/engine/function_calls.mli
index 698b62406e5..c7efe940d88 100644
--- a/src/plugins/value/engine/function_calls.mli
+++ b/src/plugins/value/engine/function_calls.mli
@@ -40,6 +40,11 @@ type analysis_target =
 val define_analysis_target:
   ?recursion_depth:int -> kinstr -> kernel_function -> analysis_target
 
+(** Returns true if the Eva analysis use the specification of the given
+    function instead of its body to interpret its calls. *)
+val use_spec_instead_of_definition:
+  ?recursion_depth:int -> kernel_function -> bool
+
 
 (** Returns true if the function has been analyzed. *)
 val is_called: kernel_function -> bool
diff --git a/src/plugins/value/engine/transfer_logic.ml b/src/plugins/value/engine/transfer_logic.ml
index d56f52ae0bb..634021c6ecc 100644
--- a/src/plugins/value/engine/transfer_logic.ml
+++ b/src/plugins/value/engine/transfer_logic.ml
@@ -54,7 +54,7 @@ let pp_p_kind fmt = function
 let post_kind kf =
   if Builtins.is_builtin_overridden kf
   then PostBuiltin
-  else if !Db.Value.use_spec_instead_of_definition kf then
+  else if Function_calls.use_spec_instead_of_definition kf then
     if Kernel_function.is_definition kf
     then PostUseSpec
     else PostLeaf
diff --git a/src/plugins/value/engine/transfer_stmt.ml b/src/plugins/value/engine/transfer_stmt.ml
index 8e3c04f6d31..205ad005015 100644
--- a/src/plugins/value/engine/transfer_stmt.ml
+++ b/src/plugins/value/engine/transfer_stmt.ml
@@ -85,7 +85,7 @@ let do_copy_at = function
    on functions whose body is analyzed. *)
 let is_determinate kf =
   let name = Kernel_function.get_name kf in
-  (warn_indeterminate kf || !Db.Value.use_spec_instead_of_definition kf)
+  (warn_indeterminate kf || Function_calls.use_spec_instead_of_definition kf)
   && not (Ast_info.is_frama_c_builtin name)
 
 let subdivide_stmt = Eva_utils.get_subdivision
diff --git a/src/plugins/value/gui_files/gui_eval.ml b/src/plugins/value/gui_files/gui_eval.ml
index 05ca7822f59..691ec61e3e2 100644
--- a/src/plugins/value/gui_files/gui_eval.ml
+++ b/src/plugins/value/gui_files/gui_eval.ml
@@ -343,7 +343,7 @@ module Make (X: Analysis.S) = struct
     let pre = pre_kf kf callstack in
     let post = X.Dom.get_cvalue_or_top post in
     let result =
-      if !Db.Value.use_spec_instead_of_definition kf then
+      if Function_calls.use_spec_instead_of_definition kf then
         None
       else
         let ret_stmt = Kernel_function.find_return kf in
@@ -395,7 +395,8 @@ module Make (X: Analysis.S) = struct
      normal termination, and only when the function is called.
      After states are not available. *)
   let callstacks_at_post kf =
-    if not (!Db.Value.use_spec_instead_of_definition kf) && results_kf_computed kf
+    if not (Function_calls.use_spec_instead_of_definition kf)
+    && results_kf_computed kf
     then
       let ret = Kernel_function.find_return kf in
       let states_before = X.get_stmt_state_by_callstack ~after:true ret in
diff --git a/src/plugins/value/legacy/eval_annots.ml b/src/plugins/value/legacy/eval_annots.ml
index 8c83557fd2a..4bf41555291 100644
--- a/src/plugins/value/legacy/eval_annots.ml
+++ b/src/plugins/value/legacy/eval_annots.ml
@@ -109,7 +109,7 @@ let mark_unreachable () =
   Visitor.visitFramacFileFunctions unreach (Ast.get ())
 
 let c_labels kf cs =
-  if !Db.Value.use_spec_instead_of_definition kf then
+  if Function_calls.use_spec_instead_of_definition kf then
     Cil_datatype.Logic_label.Map.empty
   else
     let fdec = Kernel_function.get_definition kf in
diff --git a/src/plugins/value/register.ml b/src/plugins/value/register.ml
index c1e1695ae85..8732d620e1a 100644
--- a/src/plugins/value/register.ml
+++ b/src/plugins/value/register.ml
@@ -124,14 +124,6 @@ let find_deps_term_no_transitivity_state state t =
     r.Eval_terms.ldeps
   with Eval_terms.LogicEvalError _ -> raise Db.From.Not_lval
 
-(* If the function is a builtin, or if the user has requested it, use
-   \assigns and \from clauses, that give an approximation of the result *)
-let use_spec_instead_of_definition kf =
-  not (Kernel_function.is_definition kf) ||
-  Ast_info.is_frama_c_builtin (Kernel_function.get_name kf) ||
-  Builtins.is_builtin_overridden kf ||
-  Kernel_function.Set.mem kf (Parameters.UsePrototype.get ())
-
 let eval_predicate ~pre ~here p =
   let open Eval_terms in
   let env = env_annot ~pre ~here () in
@@ -153,7 +145,8 @@ let valid_behaviors kf state =
 
 let () =
   (* Pretty-printing *)
-  Db.Value.use_spec_instead_of_definition := use_spec_instead_of_definition;
+  Db.Value.use_spec_instead_of_definition :=
+    Function_calls.use_spec_instead_of_definition;
   Db.Value.assigns_outputs_to_zone := assigns_outputs_to_zone;
   Db.Value.assigns_outputs_to_locations := assigns_outputs_to_locations;
   Db.Value.assigns_inputs_to_zone := assigns_inputs_to_zone;
-- 
GitLab