From 9a434b7a566281d1036974068d51fb466d03904b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Mon, 27 Mar 2023 14:11:09 +0200
Subject: [PATCH] [Eva] Requests: fixes evaluation of \result in
 post-conditions.

---
 src/plugins/eva/api/general_requests.ml  | 14 ++++++++------
 src/plugins/eva/api/general_requests.mli |  4 ++++
 src/plugins/eva/api/values_request.ml    | 22 ++++++++++++----------
 src/plugins/eva/utils/eva_utils.ml       |  5 +++++
 src/plugins/eva/utils/eva_utils.mli      |  4 ++++
 5 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/src/plugins/eva/api/general_requests.ml b/src/plugins/eva/api/general_requests.ml
index 1247eda023d..ca9395f89d1 100644
--- a/src/plugins/eva/api/general_requests.ml
+++ b/src/plugins/eva/api/general_requests.ml
@@ -226,8 +226,10 @@ let marker_evaluation_point = function
   | PTermLval (_, _, prop, _) | PIP prop -> property_evaluation_point prop
   | PType _ -> raise Not_found
 
-let term_lval_to_lval tlval =
-  try Logic_to_c.term_lval_to_lval tlval
+let term_lval_to_lval kf tlval =
+  try
+    let result = Option.bind kf Eva_utils.find_return_var in
+    Logic_to_c.term_lval_to_lval ?result tlval
   with Logic_to_c.No_conversion -> raise Not_found
 
 let print_value fmt loc =
@@ -242,8 +244,8 @@ let print_value fmt loc =
       Results.eval_exp expr
     | PVDecl (_, _, vi) when is_scalar vi.vtype ->
       Results.eval_var vi
-    | PTermLval (_, _, _ip, tlval) ->
-      let lval = term_lval_to_lval tlval in
+    | PTermLval (kf, _, _ip, tlval) ->
+      let lval = term_lval_to_lval kf tlval in
       if is_scalar (Cil.typeOfLval lval)
       then Results.eval_lval lval
       else raise Not_found
@@ -288,8 +290,8 @@ module EvaTaints = struct
       | PLval (_, Kstmt stmt, lval) -> Some (expr_of_lval lval, stmt)
       | PExp (_, Kstmt stmt, expr) -> Some (expr, stmt)
       | PVDecl (_, Kstmt stmt, vi) -> Some (expr_of_lval (Var vi, NoOffset), stmt)
-      | PTermLval (_, Kstmt stmt, _, tlval) ->
-        Some (term_lval_to_lval tlval |> expr_of_lval, stmt)
+      | PTermLval (kf, Kstmt stmt, _, tlval) ->
+        Some (term_lval_to_lval kf tlval |> expr_of_lval, stmt)
       | _ -> None
 
   let of_marker marker =
diff --git a/src/plugins/eva/api/general_requests.mli b/src/plugins/eva/api/general_requests.mli
index 57502fa634b..9a1c8699b3d 100644
--- a/src/plugins/eva/api/general_requests.mli
+++ b/src/plugins/eva/api/general_requests.mli
@@ -32,3 +32,7 @@ type evaluation_point =
 (* Returns the evaluation point of a marker.
    @raises Not_found if the marker cannot be evaluated. *)
 val marker_evaluation_point: Printer_tag.localizable -> evaluation_point
+
+(* Converts an ACSL lval into a C lval.
+   @raises Not_found if the conversion fails. *)
+val term_lval_to_lval: kernel_function option -> term_lval -> lval
diff --git a/src/plugins/eva/api/values_request.ml b/src/plugins/eva/api/values_request.ml
index 2796bb32d74..4fe3f15d5e4 100644
--- a/src/plugins/eva/api/values_request.ml
+++ b/src/plugins/eva/api/values_request.ml
@@ -114,12 +114,6 @@ let probe_property = function
     Ppred (Logic_const.pred_of_id_pred pred)
   | _ -> raise Not_found
 
-let probe_term_lval kf tlval =
-  try
-    let result = Option.bind kf Library_functions.get_retres_vi in
-    Plval (Logic_to_c.term_lval_to_lval ?result tlval)
-  with Logic_to_c.No_conversion -> raise Not_found
-
 let probe_marker = function
   | Printer_tag.PLval (_, _, (Var vi, NoOffset))
   | PVDecl (_, _, vi) when Cil.isFunctionType vi.vtype -> raise Not_found
@@ -127,7 +121,8 @@ let probe_marker = function
   | PExp (_, _, e) -> Pexpr e
   | PStmt (_, s) | PStmtStart (_, s) -> probe_stmt s
   | PVDecl (_, _, v) -> Plval (Var v, NoOffset)
-  | PTermLval (kf, _, _, tlval) -> probe_term_lval kf tlval
+  | PTermLval (kf, _, _, tlval) ->
+    Plval (General_requests.term_lval_to_lval kf tlval)
   | PIP property -> probe_property property
   | _ -> raise Not_found
 
@@ -475,9 +470,16 @@ module Proxy(A : Analysis.S) : EvaProxy = struct
   let eval_expr expr state =
     A.eval_expr state expr >>=: fun value -> Value value
 
-  let eval_pred predicate state =
+  let eval_pred eval_point predicate state =
+    let result =
+      match eval_point with
+      | Initial | Pre _ -> None
+      | Stmt stmt ->
+        let kf = Kernel_function.find_englobing_kf stmt in
+        Eva_utils.find_return_var kf
+    in
     let env =
-      Abstract_domain.{ states = (function _ -> A.Dom.top) ; result = None }
+      Abstract_domain.{ states = (function _ -> A.Dom.top) ; result }
     in
     let truth = A.Dom.evaluate_predicate env state predicate in
     `Value (Status truth), Alarmset.none
@@ -518,7 +520,7 @@ module Proxy(A : Analysis.S) : EvaProxy = struct
     | Pexpr expr ->
       eval_steps (Cil.typeOf expr) (eval_expr expr) eval_point callstack
     | Ppred pred ->
-      eval_steps Cil.intType (eval_pred pred) eval_point callstack
+      eval_steps Cil.intType (eval_pred eval_point pred) eval_point callstack
 end
 
 let proxy =
diff --git a/src/plugins/eva/utils/eva_utils.ml b/src/plugins/eva/utils/eva_utils.ml
index 75d902623d8..7dbc948a1e0 100644
--- a/src/plugins/eva/utils/eva_utils.ml
+++ b/src/plugins/eva/utils/eva_utils.ml
@@ -138,6 +138,11 @@ let create_new_var name typ =
 
 let is_const_write_invalid typ = Cil.typeHasQualifier "const" typ
 
+let find_return_var kf =
+  match (Kernel_function.find_return kf).skind with
+  | Return (Some ({enode = Lval ((Var vi, NoOffset))}), _) -> Some vi
+  | _ | exception Kernel_function.No_Statement -> None
+
 (* Find if a postcondition contains [\result] *)
 class postconditions_mention_result = object
   inherit Visitor.frama_c_inplace
diff --git a/src/plugins/eva/utils/eva_utils.mli b/src/plugins/eva/utils/eva_utils.mli
index 0903cdabad1..9297eee8543 100644
--- a/src/plugins/eva/utils/eva_utils.mli
+++ b/src/plugins/eva/utils/eva_utils.mli
@@ -72,6 +72,10 @@ val is_const_write_invalid: typ -> bool
 (** Detect that the type is const, and that option [-global-const] is set. In
     this case, we forbid writing in a l-value that has this type. *)
 
+val find_return_var: kernel_function -> varinfo option
+(** Returns the varinfo returned by the given function.
+    Returns None if the function returns void or has no return statement. *)
+
 val postconditions_mention_result: Cil_types.funspec -> bool
 (** Does the post-conditions of this specification mention [\result]? *)
 
-- 
GitLab