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 046a6a7f967f4de51161c85675714c523fe96060..888e5f6719ee01a513e3c06aaa09b8e30ed6c5bd 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 @@ -3,7 +3,6 @@ [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. -[eva:alarm] tests/arith/quantif.i:20: Warning: assertion got status unknown. [eva:alarm] tests/arith/quantif.i:24: Warning: function __e_acsl_assert: precondition got status unknown. [eva:alarm] tests/arith/quantif.i:24: Warning: assertion got status unknown. diff --git a/src/plugins/value/legacy/eval_terms.ml b/src/plugins/value/legacy/eval_terms.ml index 5de658b98e54d52516fc62bf0f3e08d402e3bda4..2ae8f263be7c99c80cac23faa1cc354cbbb240ed 100644 --- a/src/plugins/value/legacy/eval_terms.ml +++ b/src/plugins/value/legacy/eval_terms.ml @@ -300,14 +300,6 @@ let env_only_here state = { 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 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 @@ -322,26 +314,46 @@ let bind_logic_vars env lvs = 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 + | Ctype ctyp when Cil.isIntegralType ctyp -> + let base = Base.of_c_logic_var lv in + let size = Int.of_int (Cil.bitsSizeOf ctyp) in + let v = Cvalue.V_Or_Uninitialized.initialized V.top_int in + let state = Model.add_base_value base ~size v ~size_v:Int.one state in + state, logic_vars + | _ -> unsupported_lvar lv in let state = env_current_state env in let state, logic_vars = List.fold_left bind_one (state, env.logic_vars) lvs in overwrite_current_state { env with logic_vars } state +let copy_logic_vars ~src ~dst lvars = + let copy_one env lvar = + match Logic_utils.unroll_type lvar.lv_type with + | Linteger | Lreal -> + let value = LogicVarEnv.find lvar src.logic_vars in + let logic_vars = LogicVarEnv.add lvar value env.logic_vars in + { env with logic_vars } + | Ctype _ -> + begin + let base = Base.of_c_logic_var lvar in + match Model.find_base base (env_current_state src) with + | `Bottom | `Top -> env + | `Value offsm -> + let state = Model.add_base base offsm (env_current_state env) in + overwrite_current_state env state + end + | _ -> unsupported_lvar lvar + in + List.fold_left copy_one dst lvars + let unbind_logic_vars env lvs = 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 + | Ctype _ -> + let base = Base.of_c_logic_var lv in + Model.remove_base base state, logic_vars + | _ -> unsupported_lvar lv in let state = env_current_state env in let state, logic_vars = List.fold_left unbind_one (state, env.logic_vars) lvs in @@ -1158,9 +1170,15 @@ and eval_binop ~alarm_mode env op t1 t2 = and eval_tlhost ~alarm_mode env lv = match lv with - | TVar { lv_origin = Some v } -> - let loc = Location_Bits.inject (Base.of_varinfo v) Ival.zero in - { etype = v.vtype; + | TVar lvar -> + let base, typ = + match lvar.lv_origin, Logic_utils.unroll_type lvar.lv_type with + | Some v, _ -> Base.of_varinfo v, v.vtype + | None, Ctype typ -> Base.of_c_logic_var lvar, typ + | _ -> unsupported_lvar lvar + in + let loc = Location_Bits.inject base Ival.zero in + { etype = typ; ldeps = empty_logic_deps; eover = loc; eunder = under_loc_from_over loc; @@ -1174,14 +1192,6 @@ and eval_tlhost ~alarm_mode env lv = eunder = loc; eover = loc; empty = false; } | None -> no_result ()) - | TVar ({ lv_origin = None } as tlv) -> - let b, ty = c_logic_var tlv in - let loc = Location_Bits.inject b Ival.zero in - { etype = ty; - ldeps = empty_logic_deps; - eover = loc; - eunder = under_loc_from_over loc; - empty = false; } | TMem t -> let r = eval_term ~alarm_mode env t in let tres = match Cil.unrollType r.etype with @@ -2417,14 +2427,32 @@ and eval_predicate env pred = | Pforall (varl, p') | Pexists (varl, p') -> begin - try - let env = bind_logic_vars env varl in - let r = do_eval env p' in - match p.pred_content with - | Pexists _ -> if r = False then False else Unknown - | Pforall _ -> if r = True then True else Unknown - | _ -> assert false - with LogicEvalError _ee -> Unknown (* No error display? *) + (* If [p'] is true (or false) for all possible values of [varl], + then so is Pforall(varl, p') and Pexists(varl, p'). *) + let env = bind_logic_vars env varl in + let r = do_eval env p' in + if r <> Unknown then r else + (* Otherwise: + - if [p'] evaluates to [false] for at least some values of [varl], + then Pforall (varl, p') is false. + - if [p'] evaluates to [true] for at least some values of [varl], + then Pexists (varl, p') is true. + + In order to find such values, we reduce the environment by assuming + [p'] is true (for Pexists) or false (for Pforall), and then we + reevaluate [p'] with these values. *) + let positive = + match p.pred_content with Pforall _ -> false | _ -> true + in + let reduced_env = reduce_by_predicate ~alarm_mode env positive p' in + (* Reduce the values of logical variables [varl] in [env] according to + [reduced_env]. To be more precise, we could reduce them to + singleton values — for instance by using the interval bounds. *) + let env = copy_logic_vars ~src:reduced_env ~dst:env varl in + match p.pred_content, do_eval env p' with + | Pexists _, True -> True + | Pforall _, False -> False + | _ -> Unknown end | Pnot p -> begin match do_eval env p with diff --git a/tests/builtins/oracle/strchr.res.oracle b/tests/builtins/oracle/strchr.res.oracle index 21fd920919affc8afd1710f3d43042b975c924b3..770361f547028d044dea20eeb4bd77a6108ac9bb 100644 --- a/tests/builtins/oracle/strchr.res.oracle +++ b/tests/builtins/oracle/strchr.res.oracle @@ -23,6 +23,8 @@ [eva] tests/builtins/strchr.c:88: Call to builtin strchr [eva] tests/builtins/strchr.c:88: function strchr: precondition 'valid_string_s' got status valid. +[eva] share/libc/string.h:165: + cannot evaluate ACSL term, unsupported logic var p [eva] tests/builtins/strchr.c:88: Frama_C_show_each_mystrchr: {3} [eva] tests/builtins/strchr.c:89: assertion got status valid. [eva] tests/builtins/strchr.c:92: Call to builtin strchr diff --git a/tests/libc/oracle/stdlib_c_env.res.oracle b/tests/libc/oracle/stdlib_c_env.res.oracle index fc9107a81028a0d522e0ae1ecb02cfdafa64c96b..e39d01ba5bf5415cbb065c34c0e0af0a79d49307 100644 --- a/tests/libc/oracle/stdlib_c_env.res.oracle +++ b/tests/libc/oracle/stdlib_c_env.res.oracle @@ -9,6 +9,8 @@ [eva] share/libc/stdlib.c:114: Call to builtin strchr [eva] share/libc/stdlib.c:114: function strchr: precondition 'valid_string_s' got status valid. +[eva] share/libc/string.h:165: + cannot evaluate ACSL term, unsupported logic var p [eva] share/libc/stdlib.c:115: assertion 'string_contains_separator' got status valid. [eva] share/libc/stdlib.c:116: assertion 'name_is_not_empty' got status valid. diff --git a/tests/libc/oracle/string_c.res.oracle b/tests/libc/oracle/string_c.res.oracle index 033c83c6b476d861790f1c98a4074809e81bc6e2..401829973b44023601fe892716db53d08870ea00 100644 --- a/tests/libc/oracle/string_c.res.oracle +++ b/tests/libc/oracle/string_c.res.oracle @@ -668,6 +668,8 @@ function strchr, behavior found: postcondition 'result_in_length' got status valid. [eva] share/libc/string.h:164: function strchr, behavior found: postcondition 'result_valid_string' got status valid. +[eva] share/libc/string.h:165: + cannot evaluate ACSL term, unsupported logic var p [eva:alarm] share/libc/string.h:165: Warning: function strchr, behavior found: postcondition 'result_first_occur' got status unknown. [eva] share/libc/string.h:171: diff --git a/tests/libc/oracle/string_c_generic.res.oracle b/tests/libc/oracle/string_c_generic.res.oracle index d2f546a60acf81596b0b9778e9f97cfd59ddedba..4e1e5145535fa6ef9dd6ed43f042e6125df52320 100644 --- a/tests/libc/oracle/string_c_generic.res.oracle +++ b/tests/libc/oracle/string_c_generic.res.oracle @@ -288,6 +288,8 @@ function strchr, behavior found: postcondition 'result_in_length' got status valid. [eva] share/libc/string.h:164: function strchr, behavior found: postcondition 'result_valid_string' got status valid. +[eva] share/libc/string.h:165: + cannot evaluate ACSL term, unsupported logic var p [eva:alarm] share/libc/string.h:165: Warning: function strchr, behavior found: postcondition 'result_first_occur' got status unknown. [eva] share/libc/string.h:171: diff --git a/tests/libc/oracle/string_c_strchr.res.oracle b/tests/libc/oracle/string_c_strchr.res.oracle index 965af4a3862fe7990d7ca5c2fa9ece0a8c3fc0f8..d389a3cf5615c82c1b364e246fbcfeded5ef7fca 100644 --- a/tests/libc/oracle/string_c_strchr.res.oracle +++ b/tests/libc/oracle/string_c_strchr.res.oracle @@ -67,6 +67,8 @@ function strchr, behavior found: postcondition 'result_in_length' got status valid. [eva] share/libc/string.h:164: function strchr, behavior found: postcondition 'result_valid_string' got status valid. +[eva] share/libc/string.h:165: + cannot evaluate ACSL term, unsupported logic var p [eva:alarm] share/libc/string.h:165: Warning: function strchr, behavior found: postcondition 'result_first_occur' got status unknown. [eva] Recording results for strchr diff --git a/tests/libc/oracle/string_h.res.oracle b/tests/libc/oracle/string_h.res.oracle index 5e1e94a0719c6c96067d3788889d10788b9d8c45..fd2eaee19bf54f636ccc83358a1c4dc259534597 100644 --- a/tests/libc/oracle/string_h.res.oracle +++ b/tests/libc/oracle/string_h.res.oracle @@ -143,12 +143,8 @@ [eva] tests/libc/string_h.c:75: function strtok: precondition 'valid_string_delim' got status valid. [eva:alarm] tests/libc/string_h.c:75: Warning: - function strtok, behavior new_str: precondition 'valid_string_s_or_delim_not_found' got status unknown. -[eva:invalid-assigns] tests/libc/string_h.c:75: - Completely invalid destination for assigns clause *(s + (0 ..)). Ignoring. + function strtok, behavior new_str: precondition 'valid_string_s_or_delim_not_found' got status invalid. [eva] Done for function strtok -[eva:alarm] tests/libc/string_h.c:76: Warning: - assertion 'unreachable_if_precise' got status invalid (stopping propagation). [eva] Recording results for test_strtok [eva] Done for function test_strtok [eva] computing for function test_strtok_r <- main. @@ -232,12 +228,8 @@ [eva] tests/libc/string_h.c:105: function strtok_r: precondition 'valid_saveptr' got status valid. [eva:alarm] tests/libc/string_h.c:105: Warning: - function strtok_r, behavior new_str: precondition 'valid_string_s_or_delim_not_found' got status unknown. -[eva:invalid-assigns] tests/libc/string_h.c:105: - Completely invalid destination for assigns clause *(s + (0 ..)). Ignoring. + function strtok_r, behavior new_str: precondition 'valid_string_s_or_delim_not_found' got status invalid. [eva] Done for function strtok_r -[eva:alarm] tests/libc/string_h.c:106: Warning: - assertion 'unreachable_if_precise' got status invalid (stopping propagation). [eva] Recording results for test_strtok_r [eva] Done for function test_strtok_r [eva] computing for function strdup <- main. @@ -333,6 +325,8 @@ [eva] tests/libc/string_h.c:154: Call to builtin strchr [eva] tests/libc/string_h.c:154: function strchr: precondition 'valid_string_s' got status valid. +[eva] share/libc/string.h:165: + cannot evaluate ACSL term, unsupported logic var p [eva] computing for function strchrnul <- main. Called from tests/libc/string_h.c:155. [eva] using specification for function strchrnul diff --git a/tests/value/oracle/annot_valid.res.oracle b/tests/value/oracle/annot_valid.res.oracle index 88f57174bb9ee088a5e1aff1fccb060ef9e86128..557e8ca2b58d364e59f43e41c027e413c56505f4 100644 --- a/tests/value/oracle/annot_valid.res.oracle +++ b/tests/value/oracle/annot_valid.res.oracle @@ -17,7 +17,7 @@ [eva:alarm] tests/value/annot_valid.i:29: Warning: assertion got status unknown. [eva:alarm] tests/value/annot_valid.i:32: Warning: assertion got status unknown. [eva:alarm] tests/value/annot_valid.i:35: Warning: assertion got status unknown. -[eva:alarm] tests/value/annot_valid.i:38: Warning: assertion got status unknown. +[eva] tests/value/annot_valid.i:38: assertion got status valid. [eva] tests/value/annot_valid.i:41: assertion got status valid. [eva:alarm] tests/value/annot_valid.i:44: Warning: assertion got status invalid (stopping propagation).