From f84985d913e3129ee45d18d2b45a68ef377e68fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr> Date: Mon, 25 Mar 2024 14:45:09 +0100 Subject: [PATCH] [Eva] Eval_terms: shares code between functions reducing an exact location. --- src/plugins/eva/legacy/eval_terms.ml | 208 ++++++++++----------------- 1 file changed, 78 insertions(+), 130 deletions(-) diff --git a/src/plugins/eva/legacy/eval_terms.ml b/src/plugins/eva/legacy/eval_terms.ml index f1bb7553e45..2943a97ab7d 100644 --- a/src/plugins/eva/legacy/eval_terms.ml +++ b/src/plugins/eva/legacy/eval_terms.ml @@ -534,6 +534,15 @@ let same_etype t1 t2 = | TPtr (p1, _), TPtr (p2, _) -> Cil_datatype.Typ.equal p1 p2 | _, _ -> Cil_datatype.Typ.equal t1 t2 +(* Returns the kind of floating-point represented by a logic type, or None. *) +let logic_type_fkind = function + | Ctype typ -> begin + match Cil.unrollType typ with + | TFloat (fkind, _) -> Some fkind + | _ -> None + end + | _ -> None + let infer_binop_res_type op targ = match op with | PlusA | MinusA | Mult | Div -> targ @@ -1864,6 +1873,29 @@ and eval_term_as_exact_locs ~alarm_mode env t = (* --- Reduction by predicates --- *) (* -------------------------------------------------------------------------- *) +(* Apply [reduce] to the value of location [arg] if it is an exact location. *) +and reduce_exact_location ~alarm_mode env reduce loc = + match eval_term_as_exact_locs ~alarm_mode env loc with + | Logic_var logic_var -> + let cvalue = LogicVarEnv.find logic_var env.logic_vars in + let cvalue = reduce logic_var.lv_type cvalue in + if V.is_bottom cvalue then raise Reduce_to_bottom; + add_logic_var env logic_var cvalue + | 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' = reduce (Ctype typ_loc) v in + 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 + | exception Not_an_exact_loc + | exception LogicEvalError _ -> env + and reduce_by_valid env positive access (tset: term) = let exception DoNotReduce in (* Auxiliary function that reduces \valid(lv+offs), where lv is atomic @@ -2000,92 +2032,37 @@ and reduce_by_valid env positive access (tset: term) = and reduce_by_valid_string ~alarm_mode env positive ~wide ~access arg = (* First, reduces [arg] assuming it is a valid pointer. *) let env = reduce_by_valid env positive access arg in - try - let exact_location = eval_term_as_exact_locs ~alarm_mode env arg in - (* Reduce the cvalue [v]: - - if [positive] holds, remove bases which cannot be a valid string - as the proper strlen builtin returns bottom; - - if [positive] is false, remove bases which are a valid string, - as the proper strlen builtin returns no alarm. *) - let reduce v = - let wrapper = - if wide - then Builtins_string.frama_c_wcslen_wrapper - else Builtins_string.frama_c_strlen_wrapper - in - let aux base offset acc = - let value = Cvalue.V.inject base offset in - let v, alarms = apply_logic_builtin wrapper env [value] in - if (positive && Cvalue.V.is_bottom v) - || (not positive && not alarms) - then acc - else Cvalue.V.add base offset acc - in - Cvalue.V.fold_i aux v Cvalue.V.bottom + (* Reduce the cvalue [v]: + - if [positive] holds, remove bases which cannot be a valid string + as the proper strlen builtin returns bottom; + - if [positive] is false, remove bases which are a valid string, + as the proper strlen builtin returns no alarm. *) + let reduce _typ v = + let wrapper = + if wide + then Builtins_string.frama_c_wcslen_wrapper + else Builtins_string.frama_c_strlen_wrapper in - match exact_location with - | Logic_var logic_var -> - let cvalue = LogicVarEnv.find logic_var env.logic_vars in - let cvalue = reduce cvalue in - if V.is_bottom cvalue then raise Reduce_to_bottom; - add_logic_var env logic_var cvalue - | 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' = reduce v in - 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 aux base offset acc = + let value = Cvalue.V.inject base offset in + let v, alarms = apply_logic_builtin wrapper env [value] in + if (positive && Cvalue.V.is_bottom v) + || (not positive && not alarms) + then acc + else Cvalue.V.add base offset acc + in + Cvalue.V.fold_i aux v Cvalue.V.bottom + in + reduce_exact_location ~alarm_mode env reduce arg (* reduce [tl] so that [rl rel tr] holds *) and 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 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 - let comp = Eva_utils.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; - add_logic_var env logic_var cvalue - | 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 rtl = eval_term ~alarm_mode env tr in + let comp = Eva_utils.conv_relation rel in + let reduce typ cvalue = + Eval_op.backward_comp_left_from_type typ positive comp cvalue rtl.eover + in + reduce_exact_location ~alarm_mode env reduce tl and reduce_by_relation ~alarm_mode env positive t1 rel t2 = (* special case: t1 is a term of the form "a rel' b", @@ -2114,31 +2091,21 @@ and reduce_by_known_papp ~alarm_mode env positive li _labels args = reduces its value in [env] by using the backward propagator on fval [fval_reduce]. *) let reduce_float fval_reduce arg = - try - 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 - Eval_op.apply_on_all_locs aux locs env - with Cvalue.V.Not_based_on_null -> env + let reduce typ cvalue = + match logic_type_fkind typ with + | Some fkind -> begin + try + let v = Cvalue.V.project_float cvalue in + let kind = Fval.kind fkind in + match fval_reduce kind v with + | `Value f -> V.inject_float f + | `Bottom -> V.bottom + with Cvalue.V.Not_based_on_null -> cvalue + end + | None -> cvalue (* Better safe than sorry, we may have e.g. an int + location here *) + in + reduce_exact_location ~alarm_mode env reduce arg in (* Reduces [f] to positive or negative infinity (according to [pos]), or to the complement if [positive] is false. *) @@ -2174,29 +2141,10 @@ and 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 -> 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; - add_logic_var env logic_var reduced - | 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 - + | "\\subset", [argl;argr] when positive -> + let vr = (eval_term ~alarm_mode env argr).eover in + let reduce _typ vl = Cvalue.V.narrow vl vr in + reduce_exact_location ~alarm_mode env reduce argl | "valid_read_string", [arg] -> reduce_by_valid_string ~alarm_mode env positive ~wide:false ~access:Read arg | "valid_string", [arg] -> -- GitLab