diff --git a/src/plugins/e-acsl/tests/arith/oracle_ci/at_on-purely-logic-variables.res.oracle b/src/plugins/e-acsl/tests/arith/oracle_ci/at_on-purely-logic-variables.res.oracle
index c1d9032cb645ecaacc70d4f1af007be95b72369d..0b02e09b98b4a40aafb0895b7524d3459d38496c 100644
--- a/src/plugins/e-acsl/tests/arith/oracle_ci/at_on-purely-logic-variables.res.oracle
+++ b/src/plugins/e-acsl/tests/arith/oracle_ci/at_on-purely-logic-variables.res.oracle
@@ -59,8 +59,6 @@
   function __e_acsl_assert: precondition got status unknown.
 [eva:alarm] tests/arith/at_on-purely-logic-variables.c:7: Warning: 
   function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/arith/at_on-purely-logic-variables.c:6: Warning: 
-  function __gen_e_acsl_f: postcondition got status unknown.
 [eva:alarm] tests/arith/at_on-purely-logic-variables.c:8: Warning: 
   function __gen_e_acsl_f: postcondition got status unknown.
 [eva:alarm] tests/arith/at_on-purely-logic-variables.c:16: Warning: 
diff --git a/src/plugins/e-acsl/tests/arith/oracle_ci/quantif.res.oracle b/src/plugins/e-acsl/tests/arith/oracle_ci/quantif.res.oracle
index 5971cd977e189cd4aeeb7a9dbdc05b7bcca6432f..046a6a7f967f4de51161c85675714c523fe96060 100644
--- a/src/plugins/e-acsl/tests/arith/oracle_ci/quantif.res.oracle
+++ b/src/plugins/e-acsl/tests/arith/oracle_ci/quantif.res.oracle
@@ -1,8 +1,5 @@
 [e-acsl] beginning translation.
 [e-acsl] translation done in project "e-acsl".
-[eva:alarm] tests/arith/quantif.i:9: Warning: assertion got status unknown.
-[eva:alarm] tests/arith/quantif.i:10: Warning: assertion got status unknown.
-[eva:alarm] tests/arith/quantif.i:11: Warning: assertion got status unknown.
 [eva:alarm] tests/arith/quantif.i:15: Warning: 
   function __e_acsl_assert: precondition got status unknown.
 [eva:alarm] tests/arith/quantif.i:15: Warning: assertion got status unknown.
@@ -12,14 +9,10 @@
 [eva:alarm] tests/arith/quantif.i:24: Warning: assertion got status unknown.
 [eva:alarm] tests/arith/quantif.i:30: Warning: 
   function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/arith/quantif.i:30: Warning: assertion got status unknown.
 [eva:alarm] tests/arith/quantif.i:31: Warning: 
   function __e_acsl_assert: precondition got status unknown.
 [eva:alarm] tests/arith/quantif.i:32: Warning: 
   function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/arith/quantif.i:32: Warning: assertion got status unknown.
 [eva:alarm] tests/arith/quantif.i:33: Warning: 
   function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/arith/quantif.i:33: Warning: assertion got status unknown.
-[eva:alarm] tests/arith/quantif.i:37: Warning: assertion got status unknown.
 [eva:alarm] tests/arith/quantif.i:40: Warning: assertion got status unknown.
diff --git a/src/plugins/e-acsl/tests/examples/oracle_ci/linear_search.res.oracle b/src/plugins/e-acsl/tests/examples/oracle_ci/linear_search.res.oracle
index 691e6c40c96abdd8f892a4ee9a5730b1311440a1..99a62eef221249385b08dee71e0d519b78fc0716 100644
--- a/src/plugins/e-acsl/tests/examples/oracle_ci/linear_search.res.oracle
+++ b/src/plugins/e-acsl/tests/examples/oracle_ci/linear_search.res.oracle
@@ -4,10 +4,10 @@
   function __gen_e_acsl_search: precondition got status unknown.
 [eva:alarm] tests/examples/linear_search.i:7: Warning: 
   function __e_acsl_assert: precondition got status unknown.
-[eva:alarm] tests/examples/linear_search.i:18: Warning: 
-  loop invariant got status unknown.
 [eva:alarm] tests/examples/linear_search.i:18: Warning: 
   function __e_acsl_assert: precondition got status unknown.
+[eva:alarm] tests/examples/linear_search.i:18: Warning: 
+  loop invariant got status unknown.
 [eva:alarm] tests/examples/linear_search.i:10: Warning: 
   function __e_acsl_assert: precondition got status unknown.
 [eva:alarm] tests/examples/linear_search.i:13: Warning: 
diff --git a/src/plugins/value/legacy/eval_op.ml b/src/plugins/value/legacy/eval_op.ml
index 6fb7f3dc9fef2e5aa0c4d8e37aa62a70c3b87a43..f2eafb8ca2c7b9d097d637b1ed1fe112f42e0227 100644
--- a/src/plugins/value/legacy/eval_op.ml
+++ b/src/plugins/value/legacy/eval_op.ml
@@ -71,11 +71,15 @@ let backward_comp_float_left fkind positive comp l r =
     else V.backward_comp_float_left_false in
   back comp fkind l r
 
-let backward_comp_left_from_type t =
-  match Cil.unrollType t with
-  | TInt _ | TEnum _ | TPtr _ -> backward_comp_int_left
-  | TFloat (fk, _) ->
-    backward_comp_float_left (Fval.kind fk)
+let backward_comp_left_from_type = function
+  | Ctype typ -> begin
+      match Cil.unrollType typ with
+      | TInt _ | TEnum _ | TPtr _ -> backward_comp_int_left
+      | TFloat (fk, _) -> backward_comp_float_left (Fval.kind fk)
+      | _ -> (fun _ _ v _ -> v) (* should never occur anyway *)
+    end
+  | Linteger -> backward_comp_int_left
+  | Lreal -> backward_comp_float_left (Fval.Real)
   | _ -> (fun _ _ v _ -> v) (* should never occur anyway *)
 
 exception Unchanged
diff --git a/src/plugins/value/legacy/eval_op.mli b/src/plugins/value/legacy/eval_op.mli
index d151cccfcca11e7ee5ce913ca2b71d5ff4984dc3..99aa1c4f8866a33438703298a2c0ca3628779c05 100644
--- a/src/plugins/value/legacy/eval_op.mli
+++ b/src/plugins/value/legacy/eval_op.mli
@@ -42,7 +42,7 @@ val wrap_float: V.t -> V_Offsetmap.t option
 val wrap_long_long: V.t -> V_Offsetmap.t option
 
 val backward_comp_left_from_type:
-  Cil_types.typ ->
+  logic_type ->
   (bool -> Abstract_interp.Comp.t -> Cvalue.V.t -> Cvalue.V.t -> Cvalue.V.t)
 (** Reduction of a {!Cvalue.V.t} by [==], [!=], [>=], [>], [<=] and [<].
     [backward_comp_left_from_type positive op l r] reduces [l]
diff --git a/src/plugins/value/legacy/eval_terms.ml b/src/plugins/value/legacy/eval_terms.ml
index 44ac39bcd7a6335105d9a9d62f6213d32a08f77e..9a9fb45daa4ee4e2061a544e312932199ccfe844 100644
--- a/src/plugins/value/legacy/eval_terms.ml
+++ b/src/plugins/value/legacy/eval_terms.ml
@@ -160,7 +160,6 @@ let find_or_alarm ~alarm_mode state loc =
    to force its re-evaluation.
 *)
 
-
 type labels_states = Cvalue.Model.t Logic_label.Map.t
 
 let join_label_states m1 m2 =
@@ -168,10 +167,29 @@ let join_label_states m1 m2 =
   if m1 == m2 then m1
   else Logic_label.Map.union aux m1 m2
 
+(* Environment for mathematical variables introduced by quantifiers:
+   maps from their int identifiers to cvalues representing an over-approximation
+   of their values (either mathematical integers or mathematical reals). *)
+module LogicVarEnv = struct
+  include Cil_datatype.Logic_var.Map
+
+  let find logic_var map =
+    try find logic_var map
+    with Not_found -> unsupported_lvar logic_var
+
+  let join m1 m2 =
+    let aux _ v1 v2 = Some (Cvalue.V.join v1 v2) in
+    if m1 == m2 then m1
+    else union aux m1 m2
+end
+
+type logic_env = Cvalue.V.t LogicVarEnv.t
+
 (* The logic can refer to the state at other points of the program
    using labels. [e_cur] indicates the current label (in changes when
    evaluating the term in a \at(label,term). [e_states] associates a
-   memory state to each label. [result] contains the variable
+   memory state to each label. [logic_vars] binds mathematical variables
+   to their possible values. [result] contains the variable
    corresponding to \result; this works even with leaf functions
    without a body. [result] is None when \result is meaningless
    (e.g. the function returns void, logic outside of a function
@@ -179,12 +197,14 @@ let join_label_states m1 m2 =
 type eval_env = {
   e_cur: logic_label;
   e_states: labels_states;
+  logic_vars: logic_env;
   result: varinfo option;
 }
 
 let join_env e1 e2 = {
   e_cur = (assert (Logic_label.equal e1.e_cur e2.e_cur); e1.e_cur);
   e_states = join_label_states e1.e_states e2.e_states;
+  logic_vars = LogicVarEnv.join e1.logic_vars e2.logic_vars;
   result = (assert (e1.result == e2.result); e1.result);
 }
 
@@ -224,11 +244,13 @@ let make_env logic_env state =
   in
   { e_cur = lbl_here;
     e_states = map;
+    logic_vars = LogicVarEnv.empty;
     result = logic_env.Abstract_domain.result }
 
 let env_pre_f ~pre () = {
   e_cur = lbl_here;
   e_states = add_here pre (add_pre pre (add_init Logic_label.Map.empty));
+  logic_vars = LogicVarEnv.empty;
   result = None (* Never useful in a pre *);
 }
 
@@ -236,12 +258,14 @@ let env_post_f ?(c_labels=Logic_label.Map.empty) ~pre ~post ~result () = {
   e_cur = lbl_here;
   e_states = add_post post
       (add_here post (add_pre pre (add_old pre (add_init c_labels))));
+  logic_vars = LogicVarEnv.empty;
   result = result;
 }
 
 let env_annot ?(c_labels=Logic_label.Map.empty) ~pre ~here () = {
   e_cur = lbl_here;
   e_states = add_here here (add_pre pre (add_init c_labels));
+  logic_vars = LogicVarEnv.empty;
   result = None (* Never useful in a 'assert'. TODO: will be needed for stmt
                    contracts *);
 }
@@ -252,45 +276,64 @@ let env_assigns ~pre = {
           scheme, since we build it by evaluating the assigns... *)
   e_states = add_old pre
       (add_here pre (add_pre pre (add_init Logic_label.Map.empty)));
+  logic_vars = LogicVarEnv.empty;
   result = None (* Treated in a special way in callers *)
 }
 
 let env_only_here state = {
   e_cur = lbl_here;
   e_states = add_here state (add_init Logic_label.Map.empty);
+  logic_vars = LogicVarEnv.empty;
   result = None (* Never useful in a 'assert'. TODO: will be needed for stmt
                    contracts *);
 }
 
 (* Return the base and the type corresponding to the logic var if it is within
    the scope of the supported ones. Fail otherwise. *)
-let supported_logic_var lvi =
+let c_logic_var lvi =
   match Logic_utils.unroll_type lvi.lv_type with
   | Ctype ty when Cil.isIntegralType ty ->
     (Base.of_c_logic_var lvi), ty
   | _ -> unsupported_lvar lvi
 
+let top_float =
+  let neg_infinity = Fval.F.of_float neg_infinity
+  and pos_infinity = Fval.F.of_float infinity in
+  let fval = Fval.inject ~nan:false Fval.Real neg_infinity pos_infinity in
+  Ival.inject_float fval
+
 let bind_logic_vars env lvs =
-  let bind_one state lv =
-    try
-      let b, cty = supported_logic_var lv in
-      let size = Int.of_int (Cil.bitsSizeOf cty) in
-      let v = Cvalue.V_Or_Uninitialized.initialized V.top_int in
-      Model.add_base_value b ~size v ~size_v:Int.one state
-    with Cil.SizeOfError _ -> unsupported_lvar lv
+  let bind_one (state, logic_vars) lv =
+    let bind_logic_var ival =
+      state, LogicVarEnv.add lv (Cvalue.V.inject_ival ival) logic_vars
+    in
+    match Logic_utils.unroll_type lv.lv_type with
+    | Linteger -> bind_logic_var Ival.top
+    | Lreal -> bind_logic_var top_float
+    | _ ->
+      try
+        let b, cty = c_logic_var lv in
+        let size = Int.of_int (Cil.bitsSizeOf cty) in
+        let v = Cvalue.V_Or_Uninitialized.initialized V.top_int in
+        let state = Model.add_base_value b ~size v ~size_v:Int.one state in
+        state, logic_vars
+      with Cil.SizeOfError _ -> unsupported_lvar lv
   in
   let state = env_current_state env in
-  let state = List.fold_left bind_one state lvs in
-  overwrite_current_state env state
+  let state, logic_vars = List.fold_left bind_one (state, env.logic_vars) lvs in
+  overwrite_current_state { env with logic_vars } state
 
 let unbind_logic_vars env lvs =
-  let unbind_one state lv =
-    let b, _ = supported_logic_var lv in
-    Model.remove_base b state
+  let unbind_one (state, logic_vars) lv =
+    match Logic_utils.unroll_type lv.lv_type with
+    | Linteger | Lreal -> state, LogicVarEnv.remove lv logic_vars
+    | _ ->
+      let b, _ = c_logic_var lv in
+      Model.remove_base b state, logic_vars
   in
   let state = env_current_state env in
-  let state = List.fold_left unbind_one state lvs in
-  overwrite_current_state env state
+  let state, logic_vars = List.fold_left unbind_one (state, env.logic_vars) lvs in
+  overwrite_current_state { env with logic_vars } state
 
 let lop_to_cop op =
   match op with
@@ -351,12 +394,8 @@ let infer_binop_res_type op targ =
   | Lt | Gt | Le | Ge | Eq | Ne | LAnd | LOr ->
     Cil.intType (* those operators always return a boolean *)
 
-(* This function could probably be in Logic_utils. It computes [*tsets],
-   assuming that [tsets] has a pointer type. *)
-let deref_tsets tsets =
-  let star_tsets = Cil.mkTermMem ~addr:tsets ~off:TNoOffset in
-  let typ = Logic_typing.type_of_pointed tsets.term_type in
-  Logic_const.term (TLval star_tsets) typ
+(* Computes [*tsets], assuming that [tsets] has a pointer type. *)
+let deref_tsets tsets = Cil.mkTermMem ~addr:tsets ~off:TNoOffset
 
 
 type logic_deps = Zone.t Logic_label.Map.t
@@ -433,22 +472,21 @@ let is_noop_cast ~src_typ ~dst_typ =
   | Some (TSPtr _), Some (TSPtr _) -> true
   | _ -> false
 
-(* Note: non-constant integers can happen e.g. for sizeof of structures of an unknown size. *)
-let einteger v =
-  { etype = Cil.intType;
-    eunder = under_from_over v;
-    eover = v;
+(* Injects [cvalue] as an eval_result of type [typ] with no dependencies. *)
+let inject_no_deps typ cvalue =
+  { etype = typ;
+    eunder = under_from_over cvalue;
+    eover = cvalue;
     ldeps = empty_logic_deps }
 
+(* Integer result with no memory dependencies: constants, sizeof & alignof,
+   and values of logic variables.*)
+let einteger = inject_no_deps Cil.intType
+
 (* Note: some reals cannot be exactly represented as floats; in which
    case we do not know their under-approximation. *)
-let efloating_point etype fval =
-  let v = V.inject_float fval in
-  let eunder = under_from_over v in
-  { etype; eunder; eover = v; ldeps = empty_logic_deps }
-
-let ereal = efloating_point Cil.doubleType
-let efloat = efloating_point Cil.floatType
+let ereal fval = inject_no_deps Cil.doubleType (Cvalue.V.inject_float fval)
+let efloat fval = inject_no_deps Cil.floatType (Cvalue.V.inject_float fval)
 
 let is_true = function
   | `True | `TrueReduced _ -> true
@@ -733,15 +771,15 @@ let rec eval_term ~alarm_mode env t =
 
   (*  | TConst ((CStr | CWstr) Missing cases *)
 
-  | TAddrOf (thost, toffs) ->
-    let r = eval_thost_toffset ~alarm_mode env thost toffs in
+  | TAddrOf tlval ->
+    let r = eval_tlval ~alarm_mode env tlval in
     { etype = TPtr (r.etype, []);
       ldeps = r.ldeps;
       eunder = loc_bits_to_loc_bytes_under r.eunder;
       eover = loc_bits_to_loc_bytes r.eover }
 
-  | TStartOf (thost, toffs) ->
-    let r = eval_thost_toffset ~alarm_mode env thost toffs in
+  | TStartOf tlval ->
+    let r = eval_tlval ~alarm_mode env tlval in
     { etype = TPtr (Cil.typeOf_array_elem r.etype, []);
       ldeps = r.ldeps;
       eunder = loc_bits_to_loc_bytes_under r.eunder;
@@ -756,8 +794,15 @@ let rec eval_term ~alarm_mode env t =
     efloat Fval.(neg_infinity Single)
   | TLval (TVar {lv_name = "\\NaN"}, _) -> efloat Fval.nan
 
-  | TLval _ ->
-    let lval = eval_tlval ~alarm_mode env t in
+  (* Mathematical logic variable: uses the [logic_vars] environment. *)
+  | TLval (TVar ({ lv_type = Linteger | Lreal } as logic_var), TNoOffset) ->
+    let cvalue = LogicVarEnv.find logic_var env.logic_vars in
+    if logic_var.lv_type = Linteger
+    then einteger cvalue
+    else inject_no_deps Cil.doubleType cvalue
+
+  | TLval tlval ->
+    let lval = eval_tlval ~alarm_mode env tlval in
     let typ = lval.etype in
     let size = Eval_typ.sizeof_lval_typ typ in
     let state = env_current_state env in
@@ -1090,7 +1135,7 @@ and eval_tlhost ~alarm_mode env lv =
          eunder = loc; eover = loc }
      | None -> no_result ())
   | TVar ({ lv_origin = None } as tlv) ->
-    let b, ty = supported_logic_var tlv in
+    let b, ty = c_logic_var tlv in
     let loc = Location_Bits.inject b Ival.zero in
     { etype = ty;
       ldeps = empty_logic_deps;
@@ -1165,7 +1210,7 @@ and eval_toffset ~alarm_mode env typ toffset =
 
   | TModel _ -> unsupported "model fields"
 
-and eval_thost_toffset ~alarm_mode env thost toffs =
+and eval_tlval ~alarm_mode env (thost, toffs) =
   let rhost = eval_tlhost ~alarm_mode env thost in
   let roffset = eval_toffset ~alarm_mode env rhost.etype toffs in
   { etype = roffset.etype;
@@ -1174,14 +1219,14 @@ and eval_thost_toffset ~alarm_mode env thost toffs =
     eover = Location_Bits.shift roffset.eover rhost.eover;
   }
 
-and eval_tlval ~alarm_mode env t =
+and eval_term_as_lval ~alarm_mode env t =
   match t.term_node with
-  | TLval (thost, toffs) ->
-    eval_thost_toffset ~alarm_mode env thost toffs
+  | TLval tlval ->
+    eval_tlval ~alarm_mode env tlval
   | Tunion l ->
     let eunder, eover, deps = List.fold_left
         (fun (accunder, accover, accdeps) t ->
-           let r = eval_tlval ~alarm_mode env t in
+           let r = eval_term_as_lval ~alarm_mode env t in
            Location_Bits.link accunder r.eunder,
            Location_Bits.join accover r.eover,
            join_logic_deps accdeps r.ldeps
@@ -1197,13 +1242,13 @@ and eval_tlval ~alarm_mode env t =
       eover = Location_Bits.bottom }
   | Tat (t, lab) ->
     ignore (env_state env lab);
-    eval_tlval ~alarm_mode { env with e_cur = lab } t
+    eval_term_as_lval ~alarm_mode { env with e_cur = lab } t
   | TLogic_coerce (_lt, t) ->
     (* Logic coerce on locations (that are pointers) can only introduce
        sets, that do not change the abstract value. *)
-    eval_tlval ~alarm_mode env t
+    eval_term_as_lval ~alarm_mode env t
   | Tif (tcond, ttrue, tfalse) ->
-    eval_tif eval_tlval Location_Bits.join Location_Bits.meet ~alarm_mode env
+    eval_tif eval_term_as_lval Location_Bits.join Location_Bits.meet ~alarm_mode env
       tcond ttrue tfalse
   | _ -> ast_error (Format.asprintf "non-lval term %a" Printer.pp_term t)
 
@@ -1325,19 +1370,19 @@ and eval_extremum etype backward_left ~alarm_mode env t1 t2 =
 
 
 let eval_tlval_as_location ~alarm_mode env t =
-  let r = eval_tlval ~alarm_mode env t in
+  let r = eval_term_as_lval ~alarm_mode env t in
   let s = Eval_typ.sizeof_lval_typ r.etype in
   make_loc r.eover s
 
 let eval_tlval_as_location_with_deps ~alarm_mode env t =
-  let r = eval_tlval ~alarm_mode env t in
+  let r = eval_term_as_lval ~alarm_mode env t in
   let s = Eval_typ.sizeof_lval_typ r.etype in
   (make_loc r.eover s, r.ldeps)
 
 
 (* Return a pair of (under-approximating, over-approximating) zones. *)
 let eval_tlval_as_zone_under_over ~alarm_mode access env t =
-  let r = eval_tlval ~alarm_mode env t in
+  let r = eval_term_as_lval ~alarm_mode env t in
   let s = Eval_typ.sizeof_lval_typ r.etype in
   let under = enumerate_valid_bits_under access (make_loc r.eunder s) in
   let over = enumerate_valid_bits access (make_loc r.eover s) in
@@ -1379,52 +1424,62 @@ let pass_logic_cast exn typ trm =
 
 exception Not_an_exact_loc
 
+type exact_location =
+  | Location of typ * Locations.location
+  | Logic_var of logic_var
+
 (* Evaluate a term as a non-empty under-approximated location, or raise
    [Not_an_exact_loc]. *)
 let rec eval_term_as_exact_locs ~alarm_mode env t =
-  match t with
-  | { term_node = TLval _ } ->
-    let loc = eval_tlval ~alarm_mode env t in
+  match t.term_node with
+  | TLval (TVar ({ lv_type = Linteger | Lreal } as logic_var), TNoOffset) ->
+    Logic_var logic_var
+
+  | TLval tlval ->
+    let loc = eval_tlval ~alarm_mode env tlval in
     let typ = loc.etype in
     (* eval_term_as_exact_loc is only used for reducing values, and we must
        NOT reduce volatile locations. *)
     if Cil.typeHasQualifier "volatile" typ then raise Not_an_exact_loc;
     let loc = Locations.make_loc loc.eunder (Eval_typ.sizeof_lval_typ typ)in
     if Locations.is_bottom_loc loc then raise Not_an_exact_loc;
-    typ, loc
-
-  | { term_node = TLogic_coerce(Lreal, t)} ->
-    (* Real is not a supertype of non-finite floats because of NaN and
-       infinites, we do not want to go in the case below. Instead,
-       we check that there are no NaN/infinite, so that the subtyping
-       relation indeed holds. *)
-    let (_, locs) as r = eval_term_as_exact_locs ~alarm_mode env t in
-    let aux loc () =
-      let state = env_current_state env in
-      let v = find_or_alarm ~alarm_mode state loc in
-      let v = Cvalue_forward.reinterpret Cil.longDoubleType v in
-      let is_finite =
-        match V.project_float v with
-        | exception Cvalue.V.Not_based_on_null -> Unknown
-        | f -> Fval.is_finite f
-      in
-      match is_finite with
-      | True -> ()
-      | False | Unknown -> raise Not_an_exact_loc
-    in
-    Eval_op.apply_on_all_locs aux locs ();
-    r
+    Location (typ, loc)
+
+  | TLogic_coerce (Lreal, t) -> begin
+      match eval_term_as_exact_locs ~alarm_mode env t with
+      | Logic_var _ as x -> x
+      | Location (_, locs) as r ->
+        (* Real is not a supertype of non-finite floats because of NaN and
+           infinities, we do not want to go in the case below. Instead,
+           we check that there are no NaN/infinity, so that the subtyping
+           relation indeed holds. *)
+        let aux loc () =
+          let state = env_current_state env in
+          let v = find_or_alarm ~alarm_mode state loc in
+          let v = Cvalue_forward.reinterpret Cil.longDoubleType v in
+          let is_finite =
+            match V.project_float v with
+            | exception Cvalue.V.Not_based_on_null -> Unknown
+            | f -> Fval.is_finite f
+          in
+          match is_finite with
+          | True -> ()
+          | False | Unknown -> raise Not_an_exact_loc
+        in
+        Eval_op.apply_on_all_locs aux locs ();
+        r
+    end
 
-  | { term_node = TLogic_coerce(_, t)} ->
+  | TLogic_coerce (_, t) ->
     (* Otherwise it is always ok to pass through a TLogic_coerce, as the destination
        type is always a supertype *)
     eval_term_as_exact_locs ~alarm_mode env t
 
-  | { term_node = TCastE (ctype, t') } ->
+  | TCastE (ctype, t') ->
     pass_logic_cast Not_an_exact_loc (Ctype ctype) t';
     eval_term_as_exact_locs ~alarm_mode env t'
 
-  | { term_node = Tunion [t] } ->
+  | Tunion [t] ->
     eval_term_as_exact_locs ~alarm_mode env t
 
   | _ -> raise Not_an_exact_loc
@@ -1639,10 +1694,10 @@ let reduce_by_valid env positive access (tset: term) =
   (* reduce [t], which must be valid term-lval, so that its contents are
      a valid pointer to [typ]. If [typ] is not supplied, it is inferred
      from the type of [t]. *)
-  let aux_lval ?typ t env =
+  let aux_lval ?typ tlval env =
     try
       let alarm_mode = alarm_reduce_mode () in
-      let r = eval_tlval ~alarm_mode env t in
+      let r = eval_tlval ~alarm_mode env tlval in
       let typ = match typ with None -> r.etype | Some t -> t in
       let loc = make_loc r.eunder (Eval_typ.sizeof_lval_typ typ) in
       let r = Eval_op.apply_on_all_locs (aux_one_lval typ) loc env in
@@ -1654,14 +1709,14 @@ let reduce_by_valid env positive access (tset: term) =
     | Tunion l ->
       List.fold_left do_one env l
 
-    | TLval _ -> aux_lval t env
+    | TLval tlval -> aux_lval tlval env
 
-    | TCastE (typ, ({term_node = TLval _} as t)) -> aux_lval ~typ t env
+    | TCastE (typ, {term_node = TLval tlval}) -> aux_lval ~typ tlval env
 
-    | TAddrOf (TMem ({term_node = TLval _} as t), offs) ->
+    | TAddrOf (TMem {term_node = TLval tlval}, offs) ->
       (try
          let alarm_mode = alarm_reduce_mode () in
-         let lt = eval_tlval ~alarm_mode env t in
+         let lt = eval_tlval ~alarm_mode env tlval in
          let typ = lt.etype in
          (* Compute the offsets, that depend on the type of the lval.
             The computed list is exactly what [aux] requires *)
@@ -1672,10 +1727,10 @@ let reduce_by_valid env positive access (tset: term) =
          aux_min_max_offset aux env roffs.eunder
        with LogicEvalError _ -> env)
 
-    | TBinOp ((PlusPI | MinusPI) as op, ({term_node = TLval _} as tlv), i) ->
+    | TBinOp ((PlusPI | MinusPI) as op, {term_node = TLval tlval}, i) ->
       (try
          let alarm_mode = alarm_reduce_mode () in
-         let rtlv = eval_tlval ~alarm_mode env tlv in
+         let rtlv = eval_tlval ~alarm_mode env tlval in
          let ri = eval_term ~alarm_mode env i in
          (* Convert offsets to a simpler form if [op] is [MinusPI] *)
          let li =
@@ -1703,35 +1758,44 @@ let reduce_by_left_relation ~alarm_mode env positive tl rel tr =
   try
     let debug = false in
     if debug then Format.printf "#Left term %a@." Printer.pp_term tl;
-    let typ_loc, locs = eval_term_as_exact_locs ~alarm_mode env tl in
-    let reduce = Eval_op.backward_comp_left_from_type typ_loc in
+    let exact_location = eval_term_as_exact_locs ~alarm_mode env tl in
     let rtl = eval_term ~alarm_mode env tr in
     let cond_v = rtl.eover in
-    if debug then Format.printf "#Val right term %a@." V.pretty cond_v;
-    let aux loc env =
-      let state = env_current_state env in
-      if debug then Format.printf "#Left term as lv loc %a, typ %a@."
-          Locations.pretty loc Printer.pp_typ typ_loc;
-      let v = find_or_alarm ~alarm_mode state loc in
-      if debug then Format.printf "#Val left lval %a@." V.pretty v;
-      let v = Cvalue_forward.reinterpret typ_loc v in
-      if debug then Format.printf "#Cast left lval %a@." V.pretty v;
-      let comp = Value_util.conv_relation rel in
-      let v' = reduce positive comp v cond_v in
-      if debug then Format.printf "#Val reduced %a@." V.pretty v';
-      (* TODOBY: if loc is an int that has been silently cast to real, we end
-         up reducing an int according to a float. Instead, we should convert v
-         to  real, then cast back v_asym to the good range *)
-      if V.is_bottom v' then raise Reduce_to_bottom;
-      if V.equal v' v then
-        env
-      else
-        let state' =
-          Cvalue.Model.reduce_previous_binding state loc v'
-        in
-        overwrite_current_state env state'
-    in
-    Eval_op.apply_on_all_locs aux locs env
+    let comp = Value_util.conv_relation rel in
+    match exact_location with
+    | Logic_var logic_var ->
+      let cvalue = LogicVarEnv.find logic_var env.logic_vars in
+      let reduce = Eval_op.backward_comp_left_from_type logic_var.lv_type in
+      let cvalue = reduce positive comp cvalue cond_v in
+      if V.is_bottom cvalue then raise Reduce_to_bottom;
+      let logic_vars = LogicVarEnv.add logic_var cvalue env.logic_vars in
+      { env with logic_vars }
+    | Location (typ_loc, locs) ->
+      let reduce = Eval_op.backward_comp_left_from_type (Ctype typ_loc) in
+      if debug then Format.printf "#Val right term %a@." V.pretty cond_v;
+      let aux loc env =
+        let state = env_current_state env in
+        if debug then Format.printf "#Left term as lv loc %a, typ %a@."
+            Locations.pretty loc Printer.pp_typ typ_loc;
+        let v = find_or_alarm ~alarm_mode state loc in
+        if debug then Format.printf "#Val left lval %a@." V.pretty v;
+        let v = Cvalue_forward.reinterpret typ_loc v in
+        if debug then Format.printf "#Cast left lval %a@." V.pretty v;
+        let v' = reduce positive comp v cond_v in
+        if debug then Format.printf "#Val reduced %a@." V.pretty v';
+        (* TODOBY: if loc is an int that has been silently cast to real, we end
+           up reducing an int according to a float. Instead, we should convert v
+           to  real, then cast back v_asym to the good range *)
+        if V.is_bottom v' then raise Reduce_to_bottom;
+        if V.equal v' v then
+          env
+        else
+          let state' =
+            Cvalue.Model.reduce_previous_binding state loc v'
+          in
+          overwrite_current_state env state'
+      in
+      Eval_op.apply_on_all_locs aux locs env
   with Not_an_exact_loc | LogicEvalError _ -> env
 
 let rec reduce_by_relation ~alarm_mode env positive t1 rel t2 =
@@ -1762,27 +1826,29 @@ let reduce_by_known_papp ~alarm_mode env positive li _labels args =
      [fval_reduce]. *)
   let reduce_float fval_reduce arg =
     try
-      let typ_loc, locs = eval_term_as_exact_locs ~alarm_mode env arg in
-      let aux loc env =
-        let state = env_current_state env in
-        let v = find_or_alarm ~alarm_mode state loc in
-        let v =  Cvalue_forward.reinterpret typ_loc v in
-        let v = match Cil.unrollType typ_loc with
-          | TFloat (fkind,_) -> begin
-              let v = Cvalue.V.project_float v in
-              let kind = Fval.kind fkind in
-              match fval_reduce kind v with
-              | `Value f -> V.inject_float f
-              | `Bottom -> V.bottom
-            end
-          | _ -> (* Better safe than sorry, we may have e.g. en int location
-                    here *)
-            raise Not_an_exact_loc
+      match eval_term_as_exact_locs ~alarm_mode env arg with
+      | Logic_var _ -> env
+      | Location (typ_loc, locs) ->
+        let aux loc env =
+          let state = env_current_state env in
+          let v = find_or_alarm ~alarm_mode state loc in
+          let v =  Cvalue_forward.reinterpret typ_loc v in
+          let v = match Cil.unrollType typ_loc with
+            | TFloat (fkind,_) -> begin
+                let v = Cvalue.V.project_float v in
+                let kind = Fval.kind fkind in
+                match fval_reduce kind v with
+                | `Value f -> V.inject_float f
+                | `Bottom -> V.bottom
+              end
+            | _ -> (* Better safe than sorry, we may have e.g. an int location
+                      here *)
+              raise Not_an_exact_loc
+          in
+          let state' = Cvalue.Model.reduce_previous_binding state loc v in
+          overwrite_current_state env state'
         in
-        let state' = Cvalue.Model.reduce_previous_binding state loc v in
-        overwrite_current_state env state'
-      in
-      Eval_op.apply_on_all_locs aux locs env
+        Eval_op.apply_on_all_locs aux locs env
     with Cvalue.V.Not_based_on_null -> env
   in
   (* Reduces [f] to positive or negative infinity (according to [pos]),
@@ -1817,21 +1883,29 @@ let reduce_by_known_papp ~alarm_mode env positive li _labels args =
     reduce_by_relation ~alarm_mode env positive t1 Rgt t2
   | ("\\ge_float" | "\\ge_double"), [t1;t2] ->
     reduce_by_relation ~alarm_mode env positive t1 Rge t2
-  | "\\subset", [argl;argr] when positive ->
-    let alarm_mode = alarm_reduce_mode () in
-    let vr = (eval_term ~alarm_mode env argr).eover in
-    let _typ, locsl = eval_term_as_exact_locs ~alarm_mode env argl in
-    let aux locl env =
-      let state = env_current_state env in
-      let vl = find_or_alarm ~alarm_mode state locl in
-      let reduced = V.narrow vl vr in
-      if V.equal V.bottom reduced then raise Reduce_to_bottom;
-      let state' =
-        Cvalue.Model.reduce_previous_binding state locl reduced
-      in
-      overwrite_current_state env state'
-    in
-    Eval_op.apply_on_all_locs aux locsl env
+  | "\\subset", [argl;argr] when positive -> begin
+      let alarm_mode = alarm_reduce_mode () in
+      let vr = (eval_term ~alarm_mode env argr).eover in
+      match eval_term_as_exact_locs ~alarm_mode env argl with
+      | Logic_var logic_var ->
+        let vl = LogicVarEnv.find logic_var env.logic_vars in
+        let reduced = Cvalue.V.narrow vl vr in
+        if V.equal V.bottom reduced then raise Reduce_to_bottom;
+        let logic_vars = LogicVarEnv.add logic_var reduced env.logic_vars in
+        { env with logic_vars }
+      | Location (_typ, locsl) ->
+        let aux locl env =
+          let state = env_current_state env in
+          let vl = find_or_alarm ~alarm_mode state locl in
+          let reduced = V.narrow vl vr in
+          if V.equal V.bottom reduced then raise Reduce_to_bottom;
+          let state' =
+            Cvalue.Model.reduce_previous_binding state locl reduced
+          in
+          overwrite_current_state env state'
+        in
+        Eval_op.apply_on_all_locs aux locsl env
+    end
 
   | _ -> (* Do not fail here. We can be asked to reduce on predicates that we
             can evaluate, but on which we are not able to reduce on (yet ?).*)
@@ -2402,7 +2476,7 @@ let predicate_deps env pred =
       do_eval { env with e_cur = lbl } p
 
     | Pvalid (_, tsets) | Pvalid_read (_, tsets) | Pvalid_function tsets->
-      (eval_tlval ~alarm_mode env tsets).ldeps
+      (eval_term_as_lval ~alarm_mode env tsets).ldeps
 
     | Pinitialized (lbl, tsets) | Pdangling (lbl, tsets) ->
       let loc, deploc =
@@ -2413,7 +2487,7 @@ let predicate_deps env pred =
     | Pnot p -> do_eval env p
 
     | Pseparated ltsets ->
-      let evaled = List.map (eval_tlval ~alarm_mode env) ltsets in
+      let evaled = List.map (eval_term_as_lval ~alarm_mode env) ltsets in
       List.fold_left
         (fun acc e -> join_logic_deps acc e.ldeps)
         empty_logic_deps evaled
@@ -2465,7 +2539,7 @@ let () =
     (fun ~result state t ->
        let env = env_post_f ~pre:state ~post:state ~result () in
        try
-         let r= eval_tlval ~alarm_mode:Ignore env t in
+         let r= eval_term_as_lval ~alarm_mode:Ignore env t in
          let s = Eval_typ.sizeof_lval_typ r.etype in
          make_loc r.eunder s, make_loc r.eover s, deps_at lbl_here r.ldeps
        with LogicEvalError _ -> raise Db.Properties.Interp.No_conversion
diff --git a/tests/libc/oracle/string_c.res.oracle b/tests/libc/oracle/string_c.res.oracle
index f07006ab7b9f349145414cf225baf363499be4b9..4b2242866946650c5afa1b2f4093f6c918b70c82 100644
--- a/tests/libc/oracle/string_c.res.oracle
+++ b/tests/libc/oracle/string_c.res.oracle
@@ -769,8 +769,9 @@
   function memchr, behavior found: postcondition 'result_same_base' got status valid. (Behavior may be inactive, no reduction performed.)
 [eva] share/libc/string.h:80: 
   function memchr, behavior found: postcondition 'result_char' got status valid. (Behavior may be inactive, no reduction performed.)
-[eva:alarm] share/libc/string.h:81: Warning: 
-  function memchr, behavior found: postcondition 'result_in_str' got status unknown. (Behavior may be inactive, no reduction performed.)
+[kernel] share/libc/string.c:248: Warning: using size of 'void'
+[eva] share/libc/string.h:81: 
+  function memchr, behavior found: postcondition 'result_in_str' got status valid. (Behavior may be inactive, no reduction performed.)
 [eva:alarm] share/libc/string.h:86: Warning: 
   function memchr, behavior not_found: postcondition 'result_null' got status invalid. (Behavior may be inactive, no reduction performed.)
 [eva] Recording results for memchr
@@ -801,6 +802,8 @@
   function memchr: precondition 'initialization' got status valid.
 [eva] tests/libc/string_c.c:231: 
   function memchr: precondition 'danglingness' got status valid.
+[eva:alarm] share/libc/string.h:81: Warning: 
+  function memchr, behavior found: postcondition 'result_in_str' got status unknown. (Behavior may be inactive, no reduction performed.)
 [eva] Recording results for memchr
 [eva] Done for function memchr
 [eva] tests/libc/string_c.c:232: assertion got status valid.
diff --git a/tests/value/oracle/forall.res.oracle b/tests/value/oracle/forall.res.oracle
index 16132535368f9e2ddd498ef8720a79f326f43c42..daaa64cf446c6daed768612578c53b74ef169f47 100644
--- a/tests/value/oracle/forall.res.oracle
+++ b/tests/value/oracle/forall.res.oracle
@@ -8,7 +8,7 @@
 [eva:alarm] tests/value/forall.i:9: Warning: 
   function main: precondition got status unknown.
 [eva] tests/value/forall.i:11: assertion got status valid.
-[eva:alarm] tests/value/forall.i:12: Warning: assertion got status unknown.
+[eva] tests/value/forall.i:12: assertion got status valid.
 [eva] tests/value/forall.i:13: assertion got status valid.
 [eva:alarm] tests/value/forall.i:15: Warning: assertion got status unknown.
 [eva:alarm] tests/value/forall.i:16: Warning: assertion got status unknown.