From 5b1e64e84b3c039d418668ef17d9f30ae35e9b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr> Date: Thu, 28 Mar 2019 17:37:26 +0100 Subject: [PATCH] [Eva] New module type Abstractions.Eva: all abstractions and the evaluator. This module type simplifies the signature of functors using evaluation functions. --- Makefile | 4 +- src/plugins/value/engine/abstractions.ml | 8 ++- src/plugins/value/engine/abstractions.mli | 12 +++- src/plugins/value/engine/analysis.ml | 10 ++-- src/plugins/value/engine/compute_functions.ml | 52 +++++----------- .../value/engine/compute_functions.mli | 7 +-- .../value/engine/transfer_specification.ml | 12 ++-- .../value/engine/transfer_specification.mli | 16 ++--- src/plugins/value/engine/transfer_stmt.ml | 60 +++++++++---------- src/plugins/value/engine/transfer_stmt.mli | 16 ++--- 10 files changed, 87 insertions(+), 110 deletions(-) diff --git a/Makefile b/Makefile index f517edfe058..08279956546 100644 --- a/Makefile +++ b/Makefile @@ -913,12 +913,12 @@ PLUGIN_CMO:= slevel/split_strategy value_parameters \ domains/cvalue/cvalue_transfer domains/cvalue/cvalue_init \ domains/cvalue/cvalue_specification \ domains/cvalue/cvalue_domain \ - engine/subdivided_evaluation engine/evaluation \ + engine/subdivided_evaluation engine/evaluation engine/abstractions \ engine/recursion engine/transfer_stmt engine/transfer_specification \ engine/partitioning engine/mem_exec \ engine/legacy_partitioning engine/basic_partitioning \ engine/loop_partitioning engine/partitioned_dataflow \ - engine/initialization engine/abstractions \ + engine/initialization \ engine/compute_functions engine/analysis register PLUGIN_CMI:= values/abstract_value values/abstract_location \ engine/state_partitioning \ diff --git a/src/plugins/value/engine/abstractions.ml b/src/plugins/value/engine/abstractions.ml index a15c6bb25a6..117b2a5e4fe 100644 --- a/src/plugins/value/engine/abstractions.ml +++ b/src/plugins/value/engine/abstractions.ml @@ -83,11 +83,17 @@ end module type S = sig module Val : Value module Loc : Abstract_location.External with type value = Val.t - and type location = Precise_locs.precise_location module Dom : Abstract_domain.External with type value = Val.t and type location = Loc.location end +module type Eva = sig + include S + module Eval: Evaluation.S with type state = Dom.t + and type value = Val.t + and type loc = Loc.location + and type origin = Dom.origin +end (* -------------------------------------------------------------------------- *) (* Value Abstraction *) diff --git a/src/plugins/value/engine/abstractions.mli b/src/plugins/value/engine/abstractions.mli index 499cb28161d..9b3a1fb81ed 100644 --- a/src/plugins/value/engine/abstractions.mli +++ b/src/plugins/value/engine/abstractions.mli @@ -61,11 +61,21 @@ end module type S = sig module Val : Value module Loc : Abstract_location.External with type value = Val.t - and type location = Precise_locs.precise_location module Dom : Abstract_domain.External with type value = Val.t and type location = Loc.location end +(** Module gathering: + - the analysis abstractions: value, location and state abstractions; + - the evaluation functions for these abstractions. *) +module type Eva = sig + include S + module Eval: Evaluation.S with type state = Dom.t + and type value = Val.t + and type loc = Loc.location + and type origin = Dom.origin +end + (** Type of abstractions that use the builtin types for values and locations *) module type Standard_abstraction = Abstract_domain.Internal with type value = Cvalue.V.t diff --git a/src/plugins/value/engine/analysis.ml b/src/plugins/value/engine/analysis.ml index d11f2ec4640..402aea1875c 100644 --- a/src/plugins/value/engine/analysis.ml +++ b/src/plugins/value/engine/analysis.ml @@ -59,11 +59,13 @@ end module Make (Abstract: Abstractions.S) = struct - include Abstract - - module Eval = Evaluation.Make (Abstract.Val) (Abstract.Loc) (Abstract.Dom) + module Abstract = struct + include Abstract + module Eval = Evaluation.Make (Abstract.Val) (Abstract.Loc) (Abstract.Dom) + end - include Compute_functions.Make (Abstract) (Eval) + include Abstract + include Compute_functions.Make (Abstract) let get_stmt_state stmt = let fundec = Kernel_function.(get_definition (find_englobing_kf stmt)) in diff --git a/src/plugins/value/engine/compute_functions.ml b/src/plugins/value/engine/compute_functions.ml index 8d30fe87260..409a3b2a285 100644 --- a/src/plugins/value/engine/compute_functions.ml +++ b/src/plugins/value/engine/compute_functions.ml @@ -132,44 +132,24 @@ let () = | Sys.Signal_handle f -> prev := f with Invalid_argument _ -> () (* Ignore: SIGURSR1 is not available on Windows, and possibly on other platforms. *) -module Make - (Abstract: Abstractions.S) - (Eva: Evaluation.S with type value = Abstract.Val.t - and type origin = Abstract.Dom.origin - and type loc = Abstract.Loc.location - and type state = Abstract.Dom.t) -= struct - - module Domain = struct - include Abstract.Dom - let enter_scope kf vars state = match vars with - | [] -> state - | _ -> enter_scope kf vars state - let leave_scope kf vars state = match vars with - | [] -> state - | _ -> leave_scope kf vars state - end - module PowersetDomain = Powerset.Make (Domain) - - module Transfer = - Transfer_stmt.Make (Abstract.Val) (Abstract.Loc) (Domain) (Eva) - module Logic = Transfer_logic.Make (Domain) (PowersetDomain) +module Make (Abstract: Abstractions.Eva) = struct - module Spec = - Transfer_specification.Make - (Abstract.Val) (Abstract.Loc) (Domain) (PowersetDomain) (Logic) + module PowersetDomain = Powerset.Make (Abstract.Dom) - module Init = Initialization.Make (Abstract.Dom) (Eva) (Transfer) + module Transfer = Transfer_stmt.Make (Abstract) + module Logic = Transfer_logic.Make (Abstract.Dom) (PowersetDomain) + module Spec = Transfer_specification.Make (Abstract) (PowersetDomain) (Logic) + module Init = Initialization.Make (Abstract.Dom) (Abstract.Eval) (Transfer) module Computer = Partitioned_dataflow.Computer - (Domain) (PowersetDomain) (Transfer) (Init) (Logic) (Spec) + (Abstract.Dom) (PowersetDomain) (Transfer) (Init) (Logic) (Spec) let initial_state = Init.initial_state let get_cvalue = - match Domain.get Cvalue_domain.key with + match Abstract.Dom.get Cvalue_domain.key with | None -> fun _ -> Cvalue.Model.top | Some get -> fun state -> get state @@ -237,7 +217,7 @@ module Make (* Mem Exec *) - module MemExec = Mem_exec.Make (Abstract.Val) (Domain) + module MemExec = Mem_exec.Make (Abstract.Val) (Abstract.Dom) let compute_and_cache_call stmt call init_state = let default () = compute_using_spec_or_body (Kstmt stmt) call init_state in @@ -299,7 +279,7 @@ module Make let join_states = function | [] -> `Bottom | [state] -> `Value state - | s :: l -> `Value (List.fold_left Domain.join s l) + | s :: l -> `Value (List.fold_left Abstract.Dom.join s l) let compute_call_or_builtin stmt call state = match Builtins.find_builtin_override call.kf with @@ -333,14 +313,14 @@ module Make Builtins.apply_builtin builtin cvalue_call cvalue_state in let insert (cvalue_state, clobbered_set) = - Domain.set Locals_scoping.key clobbered_set - (Domain.set Cvalue_domain.key cvalue_state final_state) + Abstract.Dom.set Locals_scoping.key clobbered_set + (Abstract.Dom.set Cvalue_domain.key cvalue_state final_state) in let states = Bottom.bot_of_list (List.map insert cvalue_states) in Transfer.{states; cacheable; builtin=true} let compute_call = - if Domain.mem Cvalue_domain.key + if Abstract.Dom.mem Cvalue_domain.key && Abstract.Val.mem Main_values.cvalue_key && Abstract.Loc.mem Main_locations.ploc_key then compute_call_or_builtin @@ -349,7 +329,7 @@ module Make let () = Transfer.compute_call_ref := compute_call let store_initial_state kf init_state = - Domain.Store.register_initial_state (Value_util.call_stack ()) init_state; + Abstract.Dom.Store.register_initial_state (Value_util.call_stack ()) init_state; let cvalue_state = get_cvalue init_state in Db.Value.Call_Value_Callbacks.apply (cvalue_state, [kf, Kglobal]) @@ -366,7 +346,7 @@ module Make Value_util.pop_call_stack (); Value_parameters.feedback "done for function %a" Kernel_function.pretty kf; post_analysis (); - Domain.post_analysis final_state; + Abstract.Dom.post_analysis final_state; with | Db.Value.Aborted -> post_analysis_cleanup ~aborted:true; @@ -398,7 +378,7 @@ module Make let compute_from_init_state kf init_state = pre_analysis (); - Domain.Store.register_global_state (`Value init_state); + Abstract.Dom.Store.register_global_state (`Value init_state); compute kf init_state end diff --git a/src/plugins/value/engine/compute_functions.mli b/src/plugins/value/engine/compute_functions.mli index 2e04b81105c..3e1db0817b9 100644 --- a/src/plugins/value/engine/compute_functions.mli +++ b/src/plugins/value/engine/compute_functions.mli @@ -25,12 +25,7 @@ open Cil_types open Eval -module Make - (Abstract: Abstractions.S) - (Eva: Evaluation.S with type value = Abstract.Val.t - and type origin = Abstract.Dom.origin - and type loc = Abstract.Loc.location - and type state = Abstract.Dom.t) +module Make (Abstract: Abstractions.Eva) : sig (** Compute a call to the main function. *) diff --git a/src/plugins/value/engine/transfer_specification.ml b/src/plugins/value/engine/transfer_specification.ml index dc968ee3006..5515e44a3b8 100644 --- a/src/plugins/value/engine/transfer_specification.ml +++ b/src/plugins/value/engine/transfer_specification.ml @@ -165,15 +165,15 @@ let precise_loc_of_assign env assign_or_allocation = module Make - (Value: Abstract_value.External) - (Location: Abstract_location.External) - (Domain: Abstract_domain.External with type value = Value.t - and type location = Location.location) - (States: Powerset.S with type state = Domain.t) - (Logic : Transfer_logic.S with type state = Domain.t + (Abstract: Abstractions.S) + (States: Powerset.S with type state = Abstract.Dom.t) + (Logic : Transfer_logic.S with type state = Abstract.Dom.t and type states = States.t) = struct + module Domain = Abstract.Dom + module Location = Abstract.Loc + (* Most transfer functions about logic return a set of states instead of a single state, and States.empty instead of bottom. We thus use this monad to turn `Bottom into States.empty in the following for consistency. *) diff --git a/src/plugins/value/engine/transfer_specification.mli b/src/plugins/value/engine/transfer_specification.mli index 056587e6cbb..dfb86ee93c2 100644 --- a/src/plugins/value/engine/transfer_specification.mli +++ b/src/plugins/value/engine/transfer_specification.mli @@ -24,21 +24,17 @@ open Cil_types open Eval module Make - (Value: Abstract_value.External) - (Location: Abstract_location.External) - (Domain: Abstract_domain.External with type value = Value.t - and type location = Location.location) - (States: Powerset.S with type state = Domain.t) - (Logic : Transfer_logic.S with type state = Domain.t + (Abstract: Abstractions.S) + (States: Powerset.S with type state = Abstract.Dom.t) + (Logic : Transfer_logic.S with type state = Abstract.Dom.t and type states = States.t) : sig - - val treat_statement_assigns: assigns -> Domain.t -> Domain.t + val treat_statement_assigns: assigns -> Abstract.Dom.t -> Abstract.Dom.t val compute_using_specification: warn:bool -> - kinstr -> (Location.location, Value.t) call -> spec -> - Domain.t -> Domain.t list or_bottom + kinstr -> (Abstract.Loc.location, Abstract.Val.t) call -> spec -> + Abstract.Dom.t -> Abstract.Dom.t list or_bottom end diff --git a/src/plugins/value/engine/transfer_stmt.ml b/src/plugins/value/engine/transfer_stmt.ml index 2a2ac4ca72b..dedb9086728 100644 --- a/src/plugins/value/engine/transfer_stmt.ml +++ b/src/plugins/value/engine/transfer_stmt.ml @@ -101,23 +101,19 @@ module DumpFileCounters = let name = "Transfer_stmt.DumpFileCounters" end) -module Make - (Value: Abstract_value.External) - (Location: Abstract_location.External) - (Domain: Abstract_domain.External with type value = Value.t - and type location = Location.location) - (Eva: Evaluation.S with type state = Domain.state - and type value = Domain.value - and type loc = Domain.location - and type origin = Domain.origin) -= struct - - type state = Domain.state - type value = Domain.value - type location = Domain.location +module Make (Abstract: Abstractions.Eva) = struct + + module Value = Abstract.Val + module Location = Abstract.Loc + module Domain = Abstract.Dom + module Eval = Abstract.Eval + + type state = Domain.t + type value = Value.t + type location = Location.location (* Transfer functions. *) - module TF = Domain.Transfer (Eva.Valuation) + module TF = Domain.Transfer (Eval.Valuation) (* When using a product of domains, a product of states may have no concretization (if the domains have inferred incompatible properties) @@ -157,17 +153,17 @@ module Make if they lead to bottom without alarms. *) let evaluate_and_check ?valuation state expr = - let res = Eva.evaluate ?valuation state expr in + let res = Eval.evaluate ?valuation state expr in report_unreachability state res "the expression %a" Printer.pp_exp expr; res let lvaluate_and_check ~for_writing ?valuation state lval = - let res = Eva.lvaluate ~for_writing ?valuation state lval in + let res = Eval.lvaluate ~for_writing ?valuation state lval in report_unreachability state res "the lvalue %a" Printer.pp_lval lval; res let copy_lvalue_and_check ?valuation state lval = - let res = Eva.copy_lvalue ?valuation state lval in + let res = Eval.copy_lvalue ?valuation state lval in report_unreachability state res "the copy of %a" Printer.pp_lval lval; res @@ -217,7 +213,7 @@ module Make then let truth = Location.assume_no_overlap ~partial:true loc right_loc in let alarm () = Alarms.Overlap (lval, right_lval) in - Eva.interpret_truth ~alarm (loc, right_loc) truth + Eval.interpret_truth ~alarm (loc, right_loc) truth else `Value (loc, right_loc), Alarmset.none (* Checks the compatibility between the left and right locations of a copy. *) @@ -273,7 +269,7 @@ module Make (* Assumption. *) let assume state stmt expr positive = - let eval, alarms = Eva.reduce state expr positive in + let eval, alarms = Eval.reduce state expr positive in (* TODO: check not comparable. *) Alarmset.emit (Kstmt stmt) alarms; eval >>- fun valuation -> @@ -345,7 +341,7 @@ module Make | None -> default valuation expr | Some inout -> let find_loc lval = - match Eva.Valuation.find_loc valuation lval with + match Eval.Valuation.find_loc valuation lval with | `Top -> Precise_locs.loc_top | `Value record -> get record.loc in @@ -378,7 +374,7 @@ module Make reduced, and their new (more precise) value. *) let gather_reduced_arguments call valuation state = let safe_arguments = filter_safe_arguments valuation call in - let empty = Eva.Valuation.empty in + let empty = Eval.Valuation.empty in let reduce_one_argument acc argument = acc >>- fun acc -> let pre_value = match argument.avalue with @@ -393,7 +389,7 @@ module Make If the call has copied the argument, it may be uninitialized. Thus, we also avoid the backward propagation if the formal is uninitialized here. This should not happen in the Assign case above. *) - fst (Eva.copy_lvalue ~valuation:empty state lval) + fst (Eval.copy_lvalue ~valuation:empty state lval) >>- fun (_valuation, post_value) -> if Bottom.is_included Value.is_included pre_value post_value.v @@ -407,10 +403,10 @@ module Make This function reduces the [state] by assuming [expr = value] for each pair (expr, value) of [reductions]. *) let reduce_arguments reductions state = - let valuation = `Value Eva.Valuation.empty in + let valuation = `Value Eval.Valuation.empty in let reduce_one_argument valuation (argument, post_value) = valuation >>- fun valuation -> - Eva.assume ~valuation state argument.concrete post_value + Eval.assume ~valuation state argument.concrete post_value in List.fold_left reduce_one_argument valuation reductions >>-: fun valuation -> TF.update valuation state @@ -602,7 +598,7 @@ module Make let domain_show_each name arguments state = let pretty fmt expr = let pp fmt = - match fst (Eva.evaluate state expr) with + match fst (Eval.evaluate state expr) with | `Bottom -> Format.fprintf fmt "%s" (Unicode.bottom_string ()) | `Value (valuation, _value) -> show_expr valuation state fmt expr in @@ -625,7 +621,7 @@ module Make begin try let offsm = - fst (Eva.lvaluate ~for_writing:false state lval) + fst (Eval.lvaluate ~for_writing:false state lval) >>- fun (_, loc, _) -> let ploc = get_ploc loc and cvalue_state = get_cvalue state in @@ -644,7 +640,7 @@ module Make | None -> fun fmt _ _ -> Format.fprintf fmt "%s" (Unicode.top_string ()) | Some get_cval -> fun fmt expr state -> - let value = fst (Eva.evaluate state expr) >>-: snd >>-: get_cval in + let value = fst (Eval.evaluate state expr) >>-: snd >>-: get_cval in (Bottom.pretty Cvalue.V.pretty) fmt value let pretty_arguments state arguments = @@ -734,7 +730,7 @@ module Make let cacheable = ref Value_types.Cacheable in let eval = (* Resolve [funcexp] into the called kernel functions. *) - let functions, alarms = Eva.eval_function_exp funcexp ~args state in + let functions, alarms = Eval.eval_function_exp funcexp ~args state in Alarmset.emit ki_call alarms; functions >>- fun functions -> let current_kf = Value_util.current_kf () in @@ -781,7 +777,7 @@ module Make if Cil.isIntegralOrPointerType varinfo.vtype then let matched, tail = - Eva.split_by_evaluation return_expr expected_values states + Eval.split_by_evaluation return_expr expected_values states in let process (i, states, mess) = if mess then @@ -809,14 +805,14 @@ module Make let check_non_overlapping state lvs1 lvs2 = let eval_loc (acc, valuation) lval = - match fst (Eva.lvaluate ~valuation ~for_writing:false state lval) with + match fst (Eval.lvaluate ~valuation ~for_writing:false state lval) with | `Bottom -> acc, valuation | `Value (valuation, loc, _) -> (lval, loc) :: acc, valuation in let eval_list valuation lvs = List.fold_left eval_loc ([], valuation) lvs in - let list1, valuation = eval_list Eva.Valuation.empty lvs1 in + let list1, valuation = eval_list Eval.Valuation.empty lvs1 in let list2, _ = eval_list valuation lvs2 in let check acc (lval1, loc1) (lval2, loc2) = let truth = Location.assume_no_overlap ~partial:false loc1 loc2 in diff --git a/src/plugins/value/engine/transfer_stmt.mli b/src/plugins/value/engine/transfer_stmt.mli index 3fb197fdbc0..a2e64699a2e 100644 --- a/src/plugins/value/engine/transfer_stmt.mli +++ b/src/plugins/value/engine/transfer_stmt.mli @@ -61,18 +61,10 @@ module type S = sig (stmt -> (location, value) call -> state -> call_result) ref end -module Make - (Value: Abstract_value.External) - (Location: Abstract_location.External) - (Domain: Abstract_domain.External with type value = Value.t - and type location = Location.location) - (Eva: Evaluation.S with type state = Domain.state - and type value = Domain.value - and type loc = Domain.location - and type origin = Domain.origin) - : S with type state = Domain.state - and type value = Domain.value - and type location = Domain.location +module Make (Abstract: Abstractions.Eva) + : S with type state = Abstract.Dom.t + and type value = Abstract.Val.t + and type location = Abstract.Loc.location (* Local Variables: -- GitLab