diff --git a/src/plugins/eva/Eva.mli b/src/plugins/eva/Eva.mli index 1d48b8bd770c42905f1018e69de78a5447f7e547..dfe0c43c7dfc87df17a5c15b403739a53f44baa7 100644 --- a/src/plugins/eva/Eva.mli +++ b/src/plugins/eva/Eva.mli @@ -610,6 +610,22 @@ end module Logic_inout: sig + (** Returns the list of behaviors of the given function that are active for + the given initial state. *) + val valid_behaviors: + Cil_types.kernel_function -> Cvalue.Model.t -> Cil_types.behavior list + + (** Evaluation of the memory zone read by the \from part of an assigns clause, + in the given cvalue state. *) + val assigns_inputs_to_zone: + Cvalue.Model.t -> Cil_types.assigns -> Locations.Zone.t + + (** Evaluation of the memory zone written by an assigns clauses, in the given + cvalue state. *) + val assigns_outputs_to_zone: + result: Cil_types.varinfo option -> + Cvalue.Model.t -> Cil_types.assigns -> Locations.Zone.t + (** Evaluate the assigns clauses of the given function in its given pre-state, and compare them with the given froms (computed by the from plugin). Emits warnings if needed, and sets statuses to the assigns clauses. *) diff --git a/src/plugins/eva/legacy/logic_inout.ml b/src/plugins/eva/legacy/logic_inout.ml index 64edb349ce73906c2350ffd7a664064ea8fc099d..8d6cd7d02787c84b7086f9d726ad9d48d2118dbd 100644 --- a/src/plugins/eva/legacy/logic_inout.ml +++ b/src/plugins/eva/legacy/logic_inout.ml @@ -22,6 +22,68 @@ open Cil_types +let valid_behaviors kf state = + let funspec = Annotations.funspec kf in + let eval_predicate pred = + match Eval_terms.(eval_predicate (env_pre_f ~pre:state ()) pred) with + | True -> Alarmset.True + | False -> Alarmset.False + | Unknown -> Alarmset.Unknown + in + let ab = Active_behaviors.create eval_predicate funspec in + Active_behaviors.active_behaviors ab + +(* -------------------------------------------------------------------------- *) +(* --- Compute inout from assigns clauses --- *) +(* -------------------------------------------------------------------------- *) + +let eval_error_reason fmt e = + if e <> Eval_terms.CAlarm + then Eval_terms.pretty_logic_evaluation_error fmt e + +let eval_tlval_as_zone assigns kind env acc t = + try + let alarm_mode = Eval_terms.Ignore in + let zone = Eval_terms.eval_tlval_as_zone ~alarm_mode kind env t.it_content in + Locations.Zone.join acc zone + with Eval_terms.LogicEvalError e -> + let pp_clause fmt = + if kind = Read + then Printer.pp_from fmt assigns + else Printer.pp_term fmt (fst assigns).it_content + in + Self.warning ~current:true ~once:true + "Failed to interpret %sassigns clause '%t'%a" + (if kind = Read then "inputs in " else "") + pp_clause eval_error_reason e; + Locations.Zone.top + +let assigns_inputs_to_zone state assigns = + let env = Eval_terms.env_assigns ~pre:state in + let treat_asgn acc (_,ins as asgn) = + match ins with + | FromAny -> Locations.Zone.top + | From l -> List.fold_left (eval_tlval_as_zone asgn Read env) acc l + in + match assigns with + | WritesAny -> Locations.Zone.top + | Writes l -> List.fold_left treat_asgn Locations.Zone.bottom l + +let assigns_outputs_to_zone ~result state assigns = + let env = Eval_terms.env_post_f ~pre:state ~post:state ~result () in + let treat_asgn acc (out,_ as asgn) = + if Logic_utils.is_result out.it_content && result = None + then acc + else eval_tlval_as_zone asgn Write env acc out + in + match assigns with + | WritesAny -> Locations.Zone.top + | Writes l -> List.fold_left treat_asgn Locations.Zone.bottom l + +(* -------------------------------------------------------------------------- *) +(* --- Verify assigns clauses --- *) +(* -------------------------------------------------------------------------- *) + (* Eval: under-approximation of the term. Note that ACSL states that assigns clauses are evaluated in the pre-state. We skip [\result]: it is meaningless when evaluating the 'assigns' part, diff --git a/src/plugins/eva/legacy/logic_inout.mli b/src/plugins/eva/legacy/logic_inout.mli index f29202c96c739e9ae8d939674510a52ddfbb0425..f26ba262e163603ad15adff669524b8d83fa91d4 100644 --- a/src/plugins/eva/legacy/logic_inout.mli +++ b/src/plugins/eva/legacy/logic_inout.mli @@ -22,6 +22,22 @@ [@@@ api_start] +(** Returns the list of behaviors of the given function that are active for + the given initial state. *) +val valid_behaviors: + Cil_types.kernel_function -> Cvalue.Model.t -> Cil_types.behavior list + +(** Evaluation of the memory zone read by the \from part of an assigns clause, + in the given cvalue state. *) +val assigns_inputs_to_zone: + Cvalue.Model.t -> Cil_types.assigns -> Locations.Zone.t + +(** Evaluation of the memory zone written by an assigns clauses, in the given + cvalue state. *) +val assigns_outputs_to_zone: + result: Cil_types.varinfo option -> + Cvalue.Model.t -> Cil_types.assigns -> Locations.Zone.t + (** Evaluate the assigns clauses of the given function in its given pre-state, and compare them with the given froms (computed by the from plugin). Emits warnings if needed, and sets statuses to the assigns clauses. *) diff --git a/src/plugins/eva/register.ml b/src/plugins/eva/register.ml index d216a3abb25084c1526df8258b1ead0cdf93e73e..197393e0a5592251d9aaf9201d072a6e3617a309 100644 --- a/src/plugins/eva/register.ml +++ b/src/plugins/eva/register.ml @@ -34,76 +34,6 @@ let main () = let () = Db.Main.extend main -(* Functions to register in Db.Value *) - -let eval_error_reason fmt e = - if e <> Eval_terms.CAlarm - then Eval_terms.pretty_logic_evaluation_error fmt e - -let assigns_inputs_to_zone state assigns = - let env = Eval_terms.env_assigns ~pre:state in - let treat_asgn acc (_,ins as asgn) = - match ins with - | FromAny -> Zone.top - | From l -> - try - List.fold_left - (fun acc t -> - let z = - Eval_terms.eval_tlval_as_zone ~alarm_mode:Eval_terms.Ignore - Read env t.it_content - in - Zone.join acc z) - acc - l - with Eval_terms.LogicEvalError e -> - Self.warning ~current:true ~once:true - "Failed to interpret inputs in assigns clause '%a'%a" - Printer.pp_from asgn eval_error_reason e; - Zone.top - in - match assigns with - | WritesAny -> Zone.top - | Writes l -> List.fold_left treat_asgn Zone.bottom l - -let assigns_outputs_aux ~eval ~bot ~top ~join state ~result assigns = - let env = Eval_terms.env_post_f ~pre:state ~post:state ~result () in - let treat_asgn acc ({it_content = out},_) = - if Logic_utils.is_result out && result = None - then acc - else - try - let z = eval env out in - join z acc - with Eval_terms.LogicEvalError e -> - Self.warning ~current:true ~once:true - "Failed to interpret assigns clause '%a'%a" - Printer.pp_term out eval_error_reason e; - join top acc - in - match assigns with - | WritesAny -> join top bot - | Writes l -> List.fold_left treat_asgn bot l - -let assigns_outputs_to_zone = - let eval env term = - Eval_terms.eval_tlval_as_zone - ~alarm_mode:Eval_terms.Ignore Write env term - in - assigns_outputs_aux ~eval - ~bot:Locations.Zone.bottom ~top:Locations.Zone.top ~join:Locations.Zone.join - -let assigns_outputs_to_locations = - let eval env term = - Eval_terms.eval_tlval_as_location - ~alarm_mode:Eval_terms.Ignore env term - in - assigns_outputs_aux - ~eval - ~bot:[] ~top:(Locations.make_loc Locations.Location_Bits.top Int_Base.top) - ~join:(fun v l -> v :: l) - - (* "access" functions before evaluation, registered in Db.Value *) let access_value_of_lval kinstr lv = let state = Db.Value.get_state kinstr in @@ -132,30 +62,19 @@ let eval_predicate ~pre ~here p = | False -> Property_status.False_if_reachable | Unknown -> Property_status.Dont_know -let valid_behaviors kf state = - let funspec = Annotations.funspec kf in - let eval_predicate pred = - match Eval_terms.(eval_predicate (env_pre_f ~pre:state ()) pred) with - | Eval_terms.True -> Alarmset.True - | Eval_terms.False -> Alarmset.False - | Eval_terms.Unknown -> Alarmset.Unknown - in - let ab = Active_behaviors.create eval_predicate funspec in - Active_behaviors.active_behaviors ab - let () = Db.Value.is_called := Function_calls.is_called; Db.Value.callers := Function_calls.callsites; Db.Value.use_spec_instead_of_definition := Function_calls.use_spec_instead_of_definition; - Db.Value.assigns_outputs_to_zone := assigns_outputs_to_zone; - Db.Value.assigns_outputs_to_locations := assigns_outputs_to_locations; - Db.Value.assigns_inputs_to_zone := assigns_inputs_to_zone; + Db.Value.assigns_outputs_to_zone := + (fun s ~result a -> Logic_inout.assigns_outputs_to_zone ~result s a); + Db.Value.assigns_inputs_to_zone := Logic_inout.assigns_inputs_to_zone; Db.Value.access := access_value_of_lval; Db.Value.access_location := access_value_of_location; Db.Value.access_expr := access_value_of_expr; Db.Value.Logic.eval_predicate := eval_predicate; - Db.Value.valid_behaviors := valid_behaviors; + Db.Value.valid_behaviors := Logic_inout.valid_behaviors; Db.From.find_deps_term_no_transitivity_state := find_deps_term_no_transitivity_state;