diff --git a/src/plugins/value/legacy/eval_terms.ml b/src/plugins/value/legacy/eval_terms.ml
index 5cda754f5c39d4207d66d17e622972d52edb92de..e613a89787b348933b7479a352d93604a11ad6d5 100644
--- a/src/plugins/value/legacy/eval_terms.ml
+++ b/src/plugins/value/legacy/eval_terms.ml
@@ -557,29 +557,29 @@ let constraint_trange idx size_arr =
 
 (* Note: "charlen" stands for either strlen or wcslen *)
 
-(* Evaluates the logical predicates [strlen/wcslen] using str* builtins.
-   Returns [res, alarms], where [res] is the return value of [strlen]
-   ([None] the evaluation results in [bottom]). *)
-let logic_charlen_builtin wrapper state v =
+(* Applies a cvalue builtin. Returns [v, alarms], where [v] is the resulting
+   cvalue, or [None] if the builtin leads to [bottom]. *)
+let apply_logic_builtin builtin env list =
   (* the call below could in theory return Builtins.Invalid_nb_of_args,
      but logic typing constraints prevent that. *)
-  let res, alarms = wrapper state [v] in
+  let res, alarms = builtin (env_current_state env) list in
   match res with
   | None -> None
-  | Some offsm -> Some (offsm, alarms)
+  | Some offsm ->
+    let v = Extlib.the (Cvalue.V_Offsetmap.single_interval_value offsm) in
+    let v = Cvalue.V_Or_Uninitialized.get_v v in
+    Some (v, alarms)
 
 (* Never raises exceptions; instead, returns [-1,+oo] in case of alarms
    (most imprecise result possible for the logic strlen/wcslen predicates). *)
 let eval_logic_charlen wrapper env v ldeps =
   let eover =
-    match logic_charlen_builtin wrapper (env_current_state env) v with
+    match apply_logic_builtin wrapper env [v] with
     | None -> Cvalue.V.bottom
-    | Some (offsm, alarms) ->
+    | Some (v, alarms) ->
       if alarms
       then Cvalue.V.inject_ival (Ival.inject_range (Some Int.minus_one) None)
-      else
-        let v = Extlib.the (Cvalue.V_Offsetmap.single_interval_value offsm) in
-        Cvalue.V_Or_Uninitialized.get_v v
+      else v
   in
   let eunder = under_from_over eover in
   (* the C strlen function has type size_t, but the logic strlen function has
@@ -590,14 +590,12 @@ let eval_logic_charlen wrapper env v ldeps =
 (* Evaluates the logical predicates strchr/wcschr. *)
 let eval_logic_charchr builtin env s c ldeps_s ldeps_c =
   let eover =
-    match builtin (env_current_state env) [s; c] with
-    | None, _ -> Cvalue.V.bottom
-    | Some offsm, alarms ->
+    match apply_logic_builtin builtin env [s; c] with
+    | None -> Cvalue.V.bottom
+    | Some (r, alarms) ->
       if alarms
       then Cvalue.V.zero_or_one
       else
-        let v = Extlib.the (Cvalue.V_Offsetmap.single_interval_value offsm) in
-        let r = Cvalue.V_Or_Uninitialized.get_v v in
         let ctrue = Cvalue.V.contains_non_zero r
         and cfalse = Cvalue.V.contains_zero r in
         match ctrue, cfalse with
@@ -621,11 +619,9 @@ let eval_logic_memchr_off builtin env s c n =
   let n_pos = Cvalue.V.narrow positive pred_n in
   let eover =
     if Cvalue.V.is_bottom n_pos then minus_one else
-      match builtin (env_current_state env) [s.eover; c.eover; n_pos] with
-      | None, _ -> pred_n
-      | Some offsm, alarms ->
-        let v = Extlib.the (Cvalue.V_Offsetmap.single_interval_value offsm) in
-        let v = Cvalue.V_Or_Uninitialized.get_v v in
+      match apply_logic_builtin builtin env [s.eover; c.eover; n_pos] with
+      | None -> pred_n
+      | Some (v, alarms) ->
         if alarms then Cvalue.V.join pred_n v else
         if Cvalue.V.equal n_pos pred_n then v else Cvalue.V.join minus_one v
   in
@@ -1558,7 +1554,7 @@ let eval_valid_read_str ~wide env v =
     if wide then Builtins_string.frama_c_wcslen_wrapper
     else Builtins_string.frama_c_strlen_wrapper
   in
-  match logic_charlen_builtin wrapper (env_current_state env) v with
+  match apply_logic_builtin wrapper env [v] with
   | None -> (* bottom state => string always invalid *) False
   | Some (_res, alarms) ->
     if alarms