From a8f27afcda45c1c794bd08ddb076eee7784232a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr>
Date: Thu, 18 Feb 2021 15:19:30 +0100
Subject: [PATCH] [Eva] The evaluation engine gives a context record to domain
 queries.

The context currently contains the fields:
- root: is the queried expression the root expression being evaluated, or is it
  a subexpression?
- sudivision: the maximum number of subdivisions for the current evaluation.
- subdivided: is the evaluation being subdivided?

[root] is always set to false for subdivided evaluations.
---
 src/plugins/value/domains/abstract_domain.mli | 32 +++++++++++++------
 .../value/domains/apron/apron_domain.ml       |  4 +--
 .../value/domains/cvalue/cvalue_domain.ml     |  4 +--
 src/plugins/value/domains/domain_builder.ml   | 16 +++++-----
 src/plugins/value/domains/domain_lift.ml      |  8 ++---
 src/plugins/value/domains/domain_product.ml   | 12 +++----
 .../value/domains/equality/equality_domain.ml |  4 +--
 .../value/domains/gauges/gauges_domain.ml     |  4 +--
 src/plugins/value/domains/inout_domain.ml     |  4 +--
 src/plugins/value/domains/octagons.ml         |  4 +--
 src/plugins/value/domains/offsm_domain.ml     |  4 +--
 src/plugins/value/domains/simple_memory.ml    |  4 +--
 src/plugins/value/domains/symbolic_locs.ml    |  4 +--
 src/plugins/value/domains/traces_domain.ml    |  4 +--
 src/plugins/value/domains/unit_domain.ml      |  4 +--
 src/plugins/value/engine/evaluation.ml        | 10 +++---
 16 files changed, 68 insertions(+), 54 deletions(-)

diff --git a/src/plugins/value/domains/abstract_domain.mli b/src/plugins/value/domains/abstract_domain.mli
index fa7ff77ac1f..0e7d17f7ccc 100644
--- a/src/plugins/value/domains/abstract_domain.mli
+++ b/src/plugins/value/domains/abstract_domain.mli
@@ -112,6 +112,15 @@ module type Lattice = sig
       without impeding the analysis: [meet x y = `Value x] is always sound. *)
 end
 
+(** Context from the engine evaluation about a domain query. *)
+type evaluation_context = {
+  root: bool;
+  (** Is the queried expression the "root" expression being evaluated, or is it
+      a sub-expression? *)
+  subdivision: int;
+  (** Maximum number of subdivisions for the current evaluation.
+      See {!Subdivided_evaluation} for more details. *)
+}
 
 (** Extraction of information: queries for values or locations inferred by a
     domain about expressions and lvalues.
@@ -140,23 +149,26 @@ module type Queries = sig
   (** When evaluating an expression, the evaluation engine asks the domains
       for abstract values and alarms at each lvalue (via [extract_lval]) and
       each sub-expressions (via [extract_expr]).
-      In these queries, the [root] boolean is true for the root expression
-      being evaluated, and false for all its sub-terms. *)
+      In these queries:
+      - [oracle] is an evaluation function and can be used to find the answer
+        by evaluating some others expressions, especially by relational domain.
+        No recursive evaluation should be done by this function.
+      - [context] record gives some information about
+        the current evaluation. *)
 
   (** Query function for compound expressions:
-      [eval oracle t exp] returns the known value of [exp] by the state [t].
-      [oracle] is an evaluation function and can be used to find the answer
-      by evaluating some others expressions, especially by relational domain.
-      No recursive evaluation should be done by this function. *)
+      [extract_expr ~oracle context t exp] returns the known value of [exp]
+      by the state [t]. See above for more details on queries. *)
   val extract_expr :
-    oracle:(exp -> value evaluated) -> root:bool ->
+    oracle:(exp -> value evaluated) -> evaluation_context ->
     state -> exp -> (value * origin option) evaluated
 
   (** Query function for lvalues:
-      [find oracle t lval typ loc] returns the known value stored at
-      the location [loc] of the left value [lval] of type [typ]. *)
+      [extract_lval ~oracle context t lval typ loc] returns the known value
+      stored at the location [loc] of the left value [lval] of type [typ].
+      See above for more details on queries. *)
   val extract_lval :
-    oracle:(exp -> value evaluated) -> root:bool ->
+    oracle:(exp -> value evaluated) -> evaluation_context ->
     state -> lval -> typ -> location -> (value * origin option) evaluated
 
   (** [backward_location state lval typ loc v] reduces the location [loc] of the
diff --git a/src/plugins/value/domains/apron/apron_domain.ml b/src/plugins/value/domains/apron/apron_domain.ml
index 0e8d896ce66..9c2d3e85184 100644
--- a/src/plugins/value/domains/apron/apron_domain.ml
+++ b/src/plugins/value/domains/apron/apron_domain.ml
@@ -487,10 +487,10 @@ module Make (Man : Input) = struct
          apron state, whose environment raises the Failure exception. *)
       | Z.Overflow | Failure _ -> top
 
-  let extract_expr ~oracle:_ ~root:_ state expr =
+  let extract_expr ~oracle:_ _context state expr =
     compute state expr (Cil.typeOf expr)
 
-  let extract_lval ~oracle:_ ~root:_ state lval typ _loc =
+  let extract_lval ~oracle:_ _context state lval typ _loc =
     let expr = Value_util.lval_to_exp lval in
     compute state expr typ
 
diff --git a/src/plugins/value/domains/cvalue/cvalue_domain.ml b/src/plugins/value/domains/cvalue/cvalue_domain.ml
index 3aa03b76dd4..efcf6121cb5 100644
--- a/src/plugins/value/domains/cvalue/cvalue_domain.ml
+++ b/src/plugins/value/domains/cvalue/cvalue_domain.ml
@@ -201,9 +201,9 @@ module State = struct
 
   type origin = Model.origin
 
-  let extract_expr ~oracle:_ ~root:_ (s, _) expr =
+  let extract_expr ~oracle:_ _context (s, _) expr =
     Model.extract_expr s expr
-  let extract_lval ~oracle:_ ~root:_ (s, _) lval typ loc =
+  let extract_lval ~oracle:_ _context (s, _) lval typ loc =
     Model.extract_lval s lval typ loc
   let backward_location (state, _) lval typ precise_loc value =
     Model.backward_location state lval typ precise_loc value
diff --git a/src/plugins/value/domains/domain_builder.ml b/src/plugins/value/domains/domain_builder.ml
index 9c69420202f..f19b48efa12 100644
--- a/src/plugins/value/domains/domain_builder.ml
+++ b/src/plugins/value/domains/domain_builder.ml
@@ -69,8 +69,8 @@ module Make_Minimal
   let narrow x _y = `Value x
 
   let top_answer = `Value (Value.top, None), Alarmset.all
-  let extract_expr ~oracle:_ ~root:_ _state _expr = top_answer
-  let extract_lval ~oracle:_ ~root:_ _state _lval _typ _location = top_answer
+  let extract_expr ~oracle:_ _context _state _expr = top_answer
+  let extract_lval ~oracle:_ _context _state _lval _typ _location = top_answer
   let backward_location _state _lval _typ location value = `Value (location, value)
   let reduce_further _state _expr _value = []
 
@@ -187,11 +187,11 @@ module Complete_Simple_Cvalue (Domain: Simpler_domains.Simple_Cvalue)
 
     let narrow x _y = `Value x
 
-    let extract_expr ~oracle:_ ~root:_ state expr =
+    let extract_expr ~oracle:_ _context state expr =
       let v = Domain.extract_expr state expr >>-: fun v -> v, None in
       v, Alarmset.all
 
-    let extract_lval ~oracle:_ ~root:_ state lval typ location =
+    let extract_lval ~oracle:_ _context state lval typ location =
       let v = Domain.extract_lval state lval typ location >>-: fun v -> v, None in
       v, Alarmset.all
 
@@ -369,14 +369,14 @@ module Restrict
 
   let default_query = `Value (Value.top, None), Alarmset.all
 
-  let extract_expr ~oracle ~root state expr =
+  let extract_expr ~oracle context state expr =
     make_query default_query
-      (fun s -> Domain.extract_expr ~oracle ~root s expr) state
+      (fun s -> Domain.extract_expr ~oracle context s expr) state
 
-  let extract_lval ~oracle ~root state lval typ location =
+  let extract_lval ~oracle context state lval typ location =
     make_query
       default_query
-      (fun s -> Domain.extract_lval ~oracle ~root s lval typ location)
+      (fun s -> Domain.extract_lval ~oracle context s lval typ location)
       state
 
   let backward_location state lval typ location value =
diff --git a/src/plugins/value/domains/domain_lift.ml b/src/plugins/value/domains/domain_lift.ml
index a2fd37480d5..e93db09c859 100644
--- a/src/plugins/value/domains/domain_lift.ml
+++ b/src/plugins/value/domains/domain_lift.ml
@@ -53,15 +53,15 @@ module Make
   type location = Convert.extended_location
   type origin = Domain.origin
 
-  let extract_expr ~oracle ~root state exp =
+  let extract_expr ~oracle context state exp =
     let oracle exp = oracle exp >>=: Convert.restrict_val in
-    Domain.extract_expr ~oracle ~root state exp >>=: fun (value, origin) ->
+    Domain.extract_expr ~oracle context state exp >>=: fun (value, origin) ->
     Convert.extend_val value, origin
 
-  let extract_lval ~oracle ~root state lval typ loc =
+  let extract_lval ~oracle context state lval typ loc =
     let oracle exp = oracle exp >>=: Convert.restrict_val in
     let loc = Convert.restrict_loc loc in
-    Domain.extract_lval ~oracle ~root state lval typ loc
+    Domain.extract_lval ~oracle context state lval typ loc
     >>=: fun (value, origin) ->
     Convert.extend_val value, origin
 
diff --git a/src/plugins/value/domains/domain_product.ml b/src/plugins/value/domains/domain_product.ml
index 43c9f9ec3dd..683892ef2dc 100644
--- a/src/plugins/value/domains/domain_product.ml
+++ b/src/plugins/value/domains/domain_product.ml
@@ -89,15 +89,15 @@ module Make
       in
       value, alarms
 
-  let extract_expr ~oracle ~root (left, right) expr =
+  let extract_expr ~oracle context (left, right) expr =
     merge
-      (Left.extract_expr ~oracle ~root left expr)
-      (Right.extract_expr ~oracle ~root right expr)
+      (Left.extract_expr ~oracle context left expr)
+      (Right.extract_expr ~oracle context right expr)
 
-  let extract_lval ~oracle ~root (left, right) lval typ location =
+  let extract_lval ~oracle context (left, right) lval typ location =
     merge
-      (Left.extract_lval ~oracle ~root left lval typ location)
-      (Right.extract_lval ~oracle ~root right lval typ location)
+      (Left.extract_lval ~oracle context left lval typ location)
+      (Right.extract_lval ~oracle context right lval typ location)
 
   let backward_location (left, right) lval typ loc value =
     (* TODO: Loc.narrow *)
diff --git a/src/plugins/value/domains/equality/equality_domain.ml b/src/plugins/value/domains/equality/equality_domain.ml
index d616ee51836..2849ec1f6f3 100644
--- a/src/plugins/value/domains/equality/equality_domain.ml
+++ b/src/plugins/value/domains/equality/equality_domain.ml
@@ -239,12 +239,12 @@ module Make
       v, Alarmset.none
     | None -> `Value (Value.top, None), Alarmset.all
 
-  let extract_expr ~oracle ~root:_ (equalities, _, _) expr =
+  let extract_expr ~oracle _context (equalities, _, _) expr =
     let expr = Cil.constFold true expr in
     let atom_e = HCE.of_exp expr in
     coop_eval oracle equalities atom_e
 
-  let extract_lval ~oracle ~root:_ (equalities, _, _) lval _typ _location =
+  let extract_lval ~oracle _context (equalities, _, _) lval _typ _location =
     let atom_lv = HCE.of_lval lval in
     coop_eval oracle equalities atom_lv
 
diff --git a/src/plugins/value/domains/gauges/gauges_domain.ml b/src/plugins/value/domains/gauges/gauges_domain.ml
index 9ffa7ce932c..0e41b58d91d 100644
--- a/src/plugins/value/domains/gauges/gauges_domain.ml
+++ b/src/plugins/value/domains/gauges/gauges_domain.ml
@@ -1259,10 +1259,10 @@ module D_Impl : Abstract_domain.S
 
   (* TODO: it would be interesting to return something here, but we
      currently need a valuation to perform the translation. *)
-  let extract_expr ~oracle:_ ~root:_ _state _exp =
+  let extract_expr ~oracle:_ _context _state _exp =
     `Value (Cvalue.V.top, None), Alarmset.all
 
-  let extract_lval ~oracle:_ ~root:_ state _lv typ loc =
+  let extract_lval ~oracle:_ _context state _lv typ loc =
     let v =
       try
         let b = loc_to_base (Precise_locs.imprecise_location loc) typ in
diff --git a/src/plugins/value/domains/inout_domain.ml b/src/plugins/value/domains/inout_domain.ml
index 4167145500e..a51098e16eb 100644
--- a/src/plugins/value/domains/inout_domain.ml
+++ b/src/plugins/value/domains/inout_domain.ml
@@ -271,8 +271,8 @@ module Internal
 
   let top_query = `Value (Cvalue.V.top, None), Alarmset.all
 
-  let extract_expr ~oracle:_ ~root:_ _state _expr = top_query
-  let extract_lval ~oracle:_ ~root:_ _state _lv _typ _locs = top_query
+  let extract_expr ~oracle:_ _context _state _expr = top_query
+  let extract_lval ~oracle:_ _context _state _lv _typ _locs = top_query
 
   let backward_location _state _lval _typ loc value =
     `Value (loc, value)
diff --git a/src/plugins/value/domains/octagons.ml b/src/plugins/value/domains/octagons.ml
index f8149f17cf6..2be0ff0dfa9 100644
--- a/src/plugins/value/domains/octagons.ml
+++ b/src/plugins/value/domains/octagons.ml
@@ -1041,7 +1041,7 @@ module Domain = struct
 
   let top_value = `Value (Cvalue.V.top, None), Alarmset.all
 
-  let extract_expr ~oracle ~root:_ state expr =
+  let extract_expr ~oracle _context state expr =
     let evaluate_expr expr =
       match fst (oracle expr) with
       | `Bottom -> `Top (* should not happen *)
@@ -1059,7 +1059,7 @@ module Domain = struct
     then `Bottom, Alarmset.all
     else `Value (Cvalue.V.inject_ival ival, None), alarms
 
-  let extract_lval ~oracle:_ ~root:_ _t _lval _typ _loc = top_value
+  let extract_lval ~oracle:_ _context _t _lval _typ _loc = top_value
 
   let backward_location _t _lval _typ loc value = `Value (loc, value)
 
diff --git a/src/plugins/value/domains/offsm_domain.ml b/src/plugins/value/domains/offsm_domain.ml
index 236c27fe02a..a2d8355c3e2 100644
--- a/src/plugins/value/domains/offsm_domain.ml
+++ b/src/plugins/value/domains/offsm_domain.ml
@@ -163,7 +163,7 @@ module Internal  : Domain_builder.InputDomain
 
   let show_expr _valuation _state _fmt _expr = ()
 
-  let extract_expr ~oracle:_ ~root:_ _state _exp =
+  let extract_expr ~oracle:_ _context _state _exp =
     `Value (Offsm_value.Offsm.top, None), Alarmset.all
 
   (* Basic 'find' on a location *)
@@ -176,7 +176,7 @@ module Internal  : Domain_builder.InputDomain
     then Offsm_value.Offsm.top
     else O o
 
-  let extract_lval ~oracle:_ ~root:_ state _lv typ locs =
+  let extract_lval ~oracle:_ _context state _lv typ locs =
     let o =
       if Cil.typeHasQualifier "volatile" typ ||
          not (Cil.isArithmeticOrPointerType typ)
diff --git a/src/plugins/value/domains/simple_memory.ml b/src/plugins/value/domains/simple_memory.ml
index 97cb3f3e296..94a2f4c5f6c 100644
--- a/src/plugins/value/domains/simple_memory.ml
+++ b/src/plugins/value/domains/simple_memory.ml
@@ -196,11 +196,11 @@ module Make_Internal (Info: sig val name: string end) (Value: Value) = struct
   (* This function returns the information known about the location
      corresponding to [_lv], so that it may be used by the engine during
      evaluation. *)
-  let extract_lval ~oracle:_ ~root:_ state _lv typ loc =
+  let extract_lval ~oracle:_ _context state _lv typ loc =
     let v = find loc typ state in
     `Value (v, None), Alarmset.all
 
-  let extract_expr ~oracle:_ ~root:_ _state _expr =
+  let extract_expr ~oracle:_ _context _state _expr =
     `Value (Value.top, None), Alarmset.all
 
   let backward_location state _lval typ loc _value =
diff --git a/src/plugins/value/domains/symbolic_locs.ml b/src/plugins/value/domains/symbolic_locs.ml
index c56c7a592d1..2c2f51d88a2 100644
--- a/src/plugins/value/domains/symbolic_locs.ml
+++ b/src/plugins/value/domains/symbolic_locs.ml
@@ -576,12 +576,12 @@ module Internal : Domain_builder.InputDomain
      this point. Hence, the alarms have already been emitted, and we can
      return [Alarmset.none]. *)
 
-  let extract_expr ~oracle:_ ~root:_ state expr =
+  let extract_expr ~oracle:_ _context state expr =
     match Memory.find_expr expr state with
     | None -> top_query
     | Some v -> `Value (v, None), Alarmset.none
 
-  let extract_lval ~oracle:_ ~root:_ state lv _typ _locs =
+  let extract_lval ~oracle:_ _context state lv _typ _locs =
     match Memory.find_lval lv state with
     | None -> top_query
     | Some v -> `Value (v, None), Alarmset.none
diff --git a/src/plugins/value/domains/traces_domain.ml b/src/plugins/value/domains/traces_domain.ml
index 408b6f10f97..ce718b03ee1 100644
--- a/src/plugins/value/domains/traces_domain.ml
+++ b/src/plugins/value/domains/traces_domain.ml
@@ -942,8 +942,8 @@ module Internal = struct
 
   let top_query = `Value (Cvalue.V.top, None), Alarmset.all
 
-  let extract_expr ~oracle:_ ~root:_ _state _expr = top_query
-  let extract_lval ~oracle:_ ~root:_ _state _lv _typ _locs = top_query
+  let extract_expr ~oracle:_ _context _state _expr = top_query
+  let extract_lval ~oracle:_ _context _state _lv _typ _locs = top_query
 
   let backward_location _state _lval _typ loc value =
     `Value (loc, value)
diff --git a/src/plugins/value/domains/unit_domain.ml b/src/plugins/value/domains/unit_domain.ml
index 0460e6201db..5633d599dd5 100644
--- a/src/plugins/value/domains/unit_domain.ml
+++ b/src/plugins/value/domains/unit_domain.ml
@@ -55,8 +55,8 @@ module Make
   type origin
 
   let eval_top = `Value (Value.top, None), Alarmset.all
-  let extract_expr ~oracle:_ ~root:_ _ _ = eval_top
-  let extract_lval ~oracle:_ ~root:_ _ _ _ _ = eval_top
+  let extract_expr ~oracle:_ _ _ _ = eval_top
+  let extract_lval ~oracle:_ _ _ _ _ _ = eval_top
   let backward_location _ _ _ loc value = `Value (loc, value)
   let reduce_further _ _ _  = []
 
diff --git a/src/plugins/value/engine/evaluation.ml b/src/plugins/value/engine/evaluation.ml
index 52d993be37b..477dee8f4e8 100644
--- a/src/plugins/value/engine/evaluation.ml
+++ b/src/plugins/value/engine/evaluation.ml
@@ -834,12 +834,13 @@ module Make
     match expr.enode with
     | Lval lval -> eval_lval context lval
     | BinOp _ | UnOp _ | CastE _ -> begin
-        let { state; root } = context in
+        let { state; root; subdivision } = context in
         let context = { context with root = false } in
         let oracle = make_oracle context in
         let intern_value, alarms = internal_forward_eval context expr in
+        let eval_context = Abstract_domain.{ root; subdivision } in
         let domain_value, alarms' =
-          Domain.extract_expr ~oracle ~root state expr
+          Domain.extract_expr ~oracle eval_context state expr
         in
         (* Intersection of alarms, as each sets of alarms are correct
            and "complete" for the evaluation of [expr]. *)
@@ -1067,7 +1068,7 @@ module Make
       off, typ_res, volatile
 
   and eval_lval ?(indeterminate=false) context lval =
-    let { state; root } = context in
+    let { state; root; subdivision } = context in
     let context = { context with root = false } in
     let oracle = make_oracle context in
     (* Computes the location of [lval]. *)
@@ -1081,7 +1082,8 @@ module Make
     *)
     let volatile = volatile_expr || Cil.typeHasQualifier "volatile" typ_lv in
     (* Find the value of the location, if not bottom. *)
-    let v, alarms = Domain.extract_lval ~oracle ~root state lval typ_lv loc in
+    let context = Abstract_domain.{ root; subdivision } in
+    let v, alarms = Domain.extract_lval ~oracle context state lval typ_lv loc in
     let alarms = close_dereference_alarms lval alarms in
     if indeterminate
     then
-- 
GitLab