diff --git a/src/plugins/eva/Eva.mli b/src/plugins/eva/Eva.mli index 5f683ec3aac7447bb9548056c53a03f26685449c..7ddec87ce11c0f34b1fd06245e68bab3f115557c 100644 --- a/src/plugins/eva/Eva.mli +++ b/src/plugins/eva/Eva.mli @@ -181,7 +181,7 @@ end module Deps: sig (** Memory dependencies of an expression. *) - type t = Function_Froms.Deps.deps = { + type t = { data: Locations.Zone.t; (** Memory zone directly required to evaluate the given expression. *) indirect: Locations.Zone.t; @@ -634,6 +634,138 @@ module Eval: sig callers, can be cached. *) end +module Froms: sig + + module DepsOrUnassigned : sig + + type deps_or_unassigned = + | DepsBottom (** Bottom of the lattice, never bound inside a memory state + at a valid location. (May appear for bases for which the + validity does not start at 0, currently only NULL.) *) + | Unassigned (** Location has never been assigned *) + | AssignedFrom of Deps.t (** Location guaranteed to have been overwritten, + its contents depend on the [Deps.t] value *) + | MaybeAssignedFrom of Deps.t (** Location may or may not have been + overwritten *) + (** The lattice is [DepsBottom <= Unassigned], [DepsBottom <= AssignedFrom z], + [Unassigned <= MaybeAssignedFrom] and + [AssignedFrom z <= MaybeAssignedFrom z]. *) + + include Lmap_bitwise.With_default with type t = deps_or_unassigned + + val subst: (Deps.t -> Deps.t) -> t -> t + + val extract_data: t -> Locations.Zone.t + val extract_indirect: t -> Locations.Zone.t + + val may_be_unassigned: t -> bool + + val compose: t -> t -> t + (** [compose d1 d2] is the sequential composition of [d1] after [d2], ie. + the dependencies needed to execute [d1] after having executed [d2]. + It is computed as [d1] if [d1 = AssignedFrom _] (as executing [d1] + completely overwrites what [d2] wrote), and as a partial join between + [d1] and [d2] in the other cases. *) + + val pretty_precise : Format.formatter -> t -> unit + + val to_zone: t -> Locations.Zone.t + val to_deps: t -> Deps.t + end + + module Memory : sig + include Lmap_bitwise.Location_map_bitwise with type v = DepsOrUnassigned.t + + (** Prints the detail of address and data dependencies, as opposed to [pretty] + that prints the backwards-compatible union of them *) + val pretty_ind_data : Format.formatter -> t -> unit + + val find: t -> Locations.Zone.t -> Locations.Zone.t + (** Imprecise version of find, in which data and indirect dependencies are + not distinguished *) + + val find_precise: t -> Locations.Zone.t -> Deps.t + (** Precise version of find *) + + val add_binding: exact:bool -> t -> Locations.Zone.t -> Deps.t -> t + val add_binding_loc: exact:bool -> t -> Locations.location -> Deps.t -> t + val add_binding_precise_loc: + exact:bool -> Locations.access -> t -> + Precise_locs.precise_location -> Deps.t -> t + val bind_var: Cil_types.varinfo -> Deps.t -> t -> t + val unbind_var: Cil_types.varinfo -> t -> t + + val map: (DepsOrUnassigned.t -> DepsOrUnassigned.t) -> t -> t + + val compose: t -> t -> t + (** Sequential composition. See {!DepsOrUnassigned.compose}. *) + + val substitute: t -> Deps.t -> Deps.t + (** [substitute m d] applies [m] to [d] so that any dependency in [d] is + expressed using the dependencies already present in [m]. For example, + [substitute 'x From y' 'x'] returns ['y']. *) + + + (** Dependencies for [\result]. *) + + type return = Deps.t + (* Currently, this type is equal to [Deps.t]. However, some of the functions + below are more precise, and will be more useful when 'return' are + represented by a precise offsetmap. *) + + (** Default value to use for storing the dependencies of [\result] *) + val default_return: return + + (** Completely imprecise return *) + val top_return: return + + (** Completely imprecise return of the given size *) + val top_return_size: Int_Base.t -> return + + (** Add some dependencies to [\result], between bits [start] and + [start+size-1], to the [Deps.t] value; default value for [start] is 0. + If [m] is specified, the dependencies are added to it. Otherwise, + {!default_return} is used. *) + val add_to_return: + ?start:int -> size:Int_Base.t -> ?m:return -> Deps.t -> return + + val collapse_return: return -> Deps.t + end + + + + type t = { + deps_return : Memory.return + (** Dependencies for the returned value *); + deps_table : Memory.t + (** Dependencies on all the zones modified by the function *); + } + + include Datatype.S with type t := t + + val join: t -> t -> t + + val top: t + + (** Display dependencies of a function, using the function's type to improve + readability *) + val pretty_with_type: Cil_types.typ -> t Pretty_utils.formatter + + (** Display dependencies of a function, using the function's type to improve + readability, separating direct and indirect dependencies *) + val pretty_with_type_indirect: Cil_types.typ -> t Pretty_utils.formatter + + (** Extract the left part of a from result, ie. the zones that are written *) + val outputs: t -> Locations.Zone.t + + (** Extract the right part of a from result, ie. the zones on which the + written zones depend. If [include_self] is true, and the from is + of the form [x FROM y (and SELF)], [x] is added to the result; + default value is [false]. *) + val inputs: ?include_self:bool -> t -> Locations.Zone.t + +end + module Builtins: sig (** Eva analysis builtins for the cvalue domain, more efficient than their @@ -658,7 +790,7 @@ module Builtins: sig c_clobbered: Base.SetLattice.t; (** An over-approximation of the bases in which addresses of local variables might have been written *) - c_from: (Function_Froms.froms * Locations.Zone.t) option; + c_from: (Froms.t * Locations.Zone.t) option; (** If not None, the froms of the function, and its sure outputs; i.e. the dependencies of the result and of each zone written to. *) } @@ -709,7 +841,7 @@ module Cvalue_callbacks: sig (** If not None, the froms of the function, and its sure outputs; i.e. the dependencies of the result, and the dependencies of each zone written to. *) - type call_froms = (Function_Froms.froms * Locations.Zone.t) option + type call_froms = (Froms.t * Locations.Zone.t) option type analysis_kind = [ `Builtin (** A cvalue builtin is used to interpret the function. *) @@ -804,7 +936,7 @@ module Logic_inout: sig and compare them with the given froms (computed by the from plugin). Emits warnings if needed, and sets statuses to the assigns clauses. *) val verify_assigns: - Cil_types.kernel_function -> pre:Cvalue.Model.t -> Function_Froms.froms -> unit + Cil_types.kernel_function -> pre:Cvalue.Model.t -> Froms.t -> unit (** [accept_base ~formals ~locals kf b] returns [true] if and only if [b] is: diff --git a/src/plugins/eva/domains/cvalue/builtins.ml b/src/plugins/eva/domains/cvalue/builtins.ml index b128b35eed8387cf041c595f1438392a8f0bc3e9..8990420a0c8c70c1f671d24d1674b51c6a7254af 100644 --- a/src/plugins/eva/domains/cvalue/builtins.ml +++ b/src/plugins/eva/domains/cvalue/builtins.ml @@ -31,7 +31,7 @@ type cacheable = Eval.cacheable = Cacheable | NoCache | NoCacheCallers type full_result = { c_values: (Cvalue.V.t option * Cvalue.Model.t) list; c_clobbered: Base.SetLattice.t; - c_from: (Function_Froms.froms * Locations.Zone.t) option; + c_from: (Froms.t * Locations.Zone.t) option; } type call_result = diff --git a/src/plugins/eva/domains/cvalue/builtins.mli b/src/plugins/eva/domains/cvalue/builtins.mli index 1d25c32aff6cc28b5391b25368b0c3a52dce20dc..a95ff2ce8e76dbb1b0dfc6ec571e3112838d5051 100644 --- a/src/plugins/eva/domains/cvalue/builtins.mli +++ b/src/plugins/eva/domains/cvalue/builtins.mli @@ -44,7 +44,7 @@ type full_result = { c_clobbered: Base.SetLattice.t; (** An over-approximation of the bases in which addresses of local variables might have been written *) - c_from: (Function_Froms.froms * Locations.Zone.t) option; + c_from: (Froms.t * Locations.Zone.t) option; (** If not None, the froms of the function, and its sure outputs; i.e. the dependencies of the result and of each zone written to. *) } diff --git a/src/plugins/eva/domains/cvalue/builtins_malloc.ml b/src/plugins/eva/domains/cvalue/builtins_malloc.ml index 77b26cbe8cc5bcb6e6cd6812c283f612ecb56eed..3d5c3245d70535aa716a310b4e10168fe248b4ce 100644 --- a/src/plugins/eva/domains/cvalue/builtins_malloc.ml +++ b/src/plugins/eva/domains/cvalue/builtins_malloc.ml @@ -579,9 +579,8 @@ let free ~exact bases state = Locals_scoping.make_escaping ~exact ~escaping ~on_escaping ~within state in let from_changed = - let open Function_Froms in - let m = Memory.(add_binding ~exact empty !changed Deps.bottom) in - { deps_table = m; deps_return = Deps.bottom } + let m = Froms.Memory.(add_binding ~exact empty !changed Deps.bottom) in + Froms.{ deps_table = m; deps_return = Deps.bottom } in state, (from_changed, if exact then !changed else Zone.bottom) diff --git a/src/plugins/eva/domains/cvalue/builtins_memory.ml b/src/plugins/eva/domains/cvalue/builtins_memory.ml index c9d89b45120c756e9139086caca3a70f1b5a30c4..182171223f8e100043181004e3aaa2745e6731ca 100644 --- a/src/plugins/eva/domains/cvalue/builtins_memory.ml +++ b/src/plugins/eva/domains/cvalue/builtins_memory.ml @@ -74,7 +74,7 @@ let frama_c_offset _state = function let () = register_builtin "Frama_C_offset" frama_c_offset -exception Memcpy_result of (Cvalue.Model.t * Function_Froms.froms * Zone.t) +exception Memcpy_result of (Cvalue.Model.t * Froms.t * Zone.t) exception Indeterminate of V_Or_Uninitialized.t @@ -97,11 +97,10 @@ let memcpy_check_indeterminate_offsetmap offsm = (* Create a dependency [\from arg_n] where n is the nth argument of the currently called function. *) let deps_nth_arg n = - let open Function_Froms in let kf = Callstack.top_kf (Eva_utils.current_call_stack ()) in try let vi = List.nth (Kernel_function.get_formals kf) n in - Deps.add_data_dep Deps.bottom (Locations.zone_of_varinfo vi) + Deps.add_data Deps.bottom (Locations.zone_of_varinfo vi) with Failure _ -> Kernel.fatal "%d arguments expected" n @@ -126,7 +125,7 @@ let frama_c_memcpy name state actuals = in let deps_return = deps_nth_arg 0 in let empty_cfrom = - Function_Froms.({ deps_table = Memory.empty; deps_return }) + Froms.{ deps_table = Memory.empty; deps_return } in let precise_copy state = (* First step: copy the bytes we are sure to copy *) @@ -155,15 +154,15 @@ let frama_c_memcpy name state actuals = imprecision of the value analysis here. *) let exact = Location_Bits.cardinal_zero_or_one dst_bits in let deps_table = - Function_Froms.Memory.add_binding ~exact - Function_Froms.Memory.empty zone_dst deps in + Froms.Memory.add_binding ~exact Froms.Memory.empty zone_dst deps + in let sure_zone = if exact then zone_dst else Zone.bottom in (deps_table, sure_zone) in new_state, deps_table, sure_zone end else (* Nothing certain can be copied *) - (state, Function_Froms.Memory.empty, Zone.bottom) + (state, Froms.Memory.empty, Zone.bottom) in let imprecise_copy new_state precise_deps_table sure_zone = (* Second step. Size is imprecise, we will now copy some bits @@ -193,11 +192,10 @@ let frama_c_memcpy name state actuals = let zone_src = enumerate_valid_bits Locations.Read loc_src in let zone_dst = enumerate_valid_bits Locations.Write loc_dst in let deps = Deps.data zone_src in - let open Function_Froms in let deps_table = - Memory.add_binding ~exact:false precise_deps_table zone_dst deps + Froms.Memory.add_binding ~exact:false precise_deps_table zone_dst deps in - { deps_table; deps_return } + Froms.{ deps_table; deps_return } in try (* We try to iter on all the slices inside the value of slice. @@ -274,9 +272,10 @@ let frama_c_memcpy name state actuals = raise (Memcpy_result (state, empty_cfrom, Zone.bottom)); let (precise_state,precise_deps_table,sure_zone) = precise_copy state in if Option.fold ~none:false ~some:(Int.equal min) max then - (let open Function_Froms in - let c_from = { deps_table = precise_deps_table; deps_return } in - raise (Memcpy_result (precise_state, c_from, sure_zone))); + begin + let c_from = Froms.{ deps_table = precise_deps_table; deps_return } in + raise (Memcpy_result (precise_state, c_from, sure_zone)) + end; imprecise_copy precise_state precise_deps_table sure_zone with | Memcpy_result (new_state,c_from,sure_zone) -> @@ -361,16 +360,16 @@ let frama_c_memset_imprecise state dst_lval dst v size = with Not_found -> (new_state,Zone.bottom) (* from find_lonely_key + explicit raise *) in let c_from = - let open Function_Froms in let value_dep = deps_nth_arg 1 in + let empty = Froms.Memory.empty in let deps_table = - Memory.add_binding ~exact:false Memory.empty over_zone value_dep + Froms.Memory.add_binding ~exact:false empty over_zone value_dep in let deps_table = - Memory.add_binding ~exact:true deps_table sure_zone value_dep + Froms.Memory.add_binding ~exact:true deps_table sure_zone value_dep in let deps_return = deps_nth_arg 0 in - { deps_table; deps_return } + Froms.{ deps_table; deps_return } in Builtins.Full { Builtins.c_values = [Some dst, new_state']; @@ -573,15 +572,14 @@ let frama_c_memset_precise state dst_lval dst v (exp_size, size) = let dst_loc = Locations.loc_bytes_to_loc_bits dst in let (c_from,dst_zone) = let input = deps_nth_arg 1 in - let open Function_Froms in let size_bits = Integer.mul size (Bit_utils.sizeofchar ())in let dst_location = Locations.make_loc dst_loc (Int_Base.Value size_bits) in let dst_zone = Locations.(enumerate_valid_bits Write dst_location) in let deps_table = - Function_Froms.Memory.add_binding ~exact:true - Function_Froms.Memory.empty dst_zone input in + Froms.Memory.add_binding ~exact:true Froms.Memory.empty dst_zone input + in let deps_return = deps_nth_arg 0 in - let c_from = { deps_table; deps_return } in + let c_from = Froms.{ deps_table; deps_return } in c_from,dst_zone in let _ = c_from in diff --git a/src/plugins/eva/dune b/src/plugins/eva/dune index 72c9794026a8ffa276dce764e63e3420a14e35ea..a828561d21824a349f0f222e217576eeceb50f34 100644 --- a/src/plugins/eva/dune +++ b/src/plugins/eva/dune @@ -113,7 +113,8 @@ (deps gen-api.sh Eva.header engine/analysis.mli types/callstack.mli types/deps.mli utils/results.mli parameters.mli - utils/eva_annotations.mli eval.mli domains/cvalue/builtins.mli - utils/cvalue_callbacks.mli legacy/logic_inout.mli utils/eva_results.mli + utils/eva_annotations.mli eval.mli types/froms.mli + domains/cvalue/builtins.mli utils/cvalue_callbacks.mli legacy/logic_inout.mli + utils/eva_results.mli utils/unit_tests.mli) (action (run bash %{deps}))) diff --git a/src/plugins/eva/engine/compute_functions.ml b/src/plugins/eva/engine/compute_functions.ml index 88b6280b2e75a83b72bf2a90b23921754ba17269..7e02649b28a12c7f8526a6eea4732484e09ddde9 100644 --- a/src/plugins/eva/engine/compute_functions.ml +++ b/src/plugins/eva/engine/compute_functions.ml @@ -35,7 +35,7 @@ let clear_caches () = Cvalue.Model.clear_caches (); Locations.Location_Bytes.clear_caches (); Locations.Zone.clear_caches (); - Function_Froms.Memory.clear_caches () + Froms.Memory.clear_caches () let () = State.add_hook_on_update Self.state clear_caches diff --git a/src/plugins/eva/gui/gui_eval.ml b/src/plugins/eva/gui/gui_eval.ml index 3205c66f1626cdcf9cfbafd72be6a11af0af5b2c..bee771c2d1f03c870818a8f36f27e766dfa7969a 100644 --- a/src/plugins/eva/gui/gui_eval.ml +++ b/src/plugins/eva/gui/gui_eval.ml @@ -86,7 +86,7 @@ let clear_caches () = Cvalue.Model.clear_caches (); Locations.Location_Bytes.clear_caches (); Locations.Zone.clear_caches (); - Function_Froms.Memory.clear_caches () + Froms.Memory.clear_caches () module type S = sig module Analysis : Analysis.S diff --git a/src/plugins/eva/legacy/logic_inout.ml b/src/plugins/eva/legacy/logic_inout.ml index e1239bd8a790afd2dc0b7c0f75b064666f05aa2b..4c1a07385881578a2b1fbcec1fd9ab11f7ccb533 100644 --- a/src/plugins/eva/legacy/logic_inout.ml +++ b/src/plugins/eva/legacy/logic_inout.ml @@ -150,11 +150,10 @@ let eval_assigns_from pre_state it = let check_from pre_state asgn assigns_zone from found_froms = let open Locations in let found_deps = - let open Function_Froms in if Logic_utils.is_result asgn.it_content then - found_froms.deps_return + found_froms.Froms.deps_return else - Memory.find_precise found_froms.deps_table assigns_zone + Froms.Memory.find_precise found_froms.deps_table assigns_zone in let (indirect_deps,direct_deps) = let filter x = List.mem "indirect" x.it_content.term_name in @@ -214,7 +213,7 @@ let check_fct_assigns kf ab ~pre_state found_froms = let behaviors = Annotations.behaviors kf in (* Under-approximation of the union. *) let link zones = List.fold_left Zone.link Zone.bottom zones in - let outputs = Function_Froms.outputs found_froms in + let outputs = Froms.outputs found_froms in let check_for_behavior b = let activity = Active_behaviors.is_active ab b in match activity with diff --git a/src/plugins/eva/legacy/logic_inout.mli b/src/plugins/eva/legacy/logic_inout.mli index ddec2c39239451d647383b453d55c3800a534a7c..d55e8ccd6ef71ddd0c035f61a2dba75f8467d227 100644 --- a/src/plugins/eva/legacy/logic_inout.mli +++ b/src/plugins/eva/legacy/logic_inout.mli @@ -66,7 +66,7 @@ val assigns_tlval_to_zones: and compare them with the given froms (computed by the from plugin). Emits warnings if needed, and sets statuses to the assigns clauses. *) val verify_assigns: - Cil_types.kernel_function -> pre:Cvalue.Model.t -> Function_Froms.froms -> unit + Cil_types.kernel_function -> pre:Cvalue.Model.t -> Froms.t -> unit (** [accept_base ~formals ~locals kf b] returns [true] if and only if [b] is: diff --git a/src/plugins/eva/types/deps.ml b/src/plugins/eva/types/deps.ml index bfd9904fecca0b2be9dbbaa825a663f56526bd64..2f6bad3f7a3fd2b6929de54743354bf3c206498f 100644 --- a/src/plugins/eva/types/deps.ml +++ b/src/plugins/eva/types/deps.ml @@ -22,7 +22,7 @@ module Zone = Locations.Zone -type deps = Function_Froms.Deps.deps = { +type deps = { data: Zone.t; indirect: Zone.t; } diff --git a/src/plugins/eva/types/deps.mli b/src/plugins/eva/types/deps.mli index e63413d1d8757e52e986f39415ffc34526595403..a30399e8e540450f5be762e719d3ffd86db01176 100644 --- a/src/plugins/eva/types/deps.mli +++ b/src/plugins/eva/types/deps.mli @@ -23,7 +23,7 @@ [@@@ api_start] (** Memory dependencies of an expression. *) -type t = Function_Froms.Deps.deps = { +type t = { data: Locations.Zone.t; (** Memory zone directly required to evaluate the given expression. *) indirect: Locations.Zone.t; diff --git a/src/kernel_services/abstract_interp/function_Froms.ml b/src/plugins/eva/types/froms.ml similarity index 84% rename from src/kernel_services/abstract_interp/function_Froms.ml rename to src/plugins/eva/types/froms.ml index f6f2f5e8a931121cbb58b2d66caf6c5fdaa4e3e5..d9adc49442dd575a1fd27fab4db657b782e907a0 100644 --- a/src/kernel_services/abstract_interp/function_Froms.ml +++ b/src/plugins/eva/types/froms.ml @@ -22,107 +22,6 @@ open Locations -module Deps = -struct - - type deps = { - data: Zone.t; - indirect: Zone.t; - } - - let to_zone {data; indirect} = Zone.join data indirect - - module DatatypeFromDeps = Datatype.Make(struct - type t = deps - - let name = "Function_Froms.Deps.from_deps" - - let hash fd = - Zone.hash fd.data + 37 * Zone.hash fd.indirect - - let compare fd1 fd2 = - let c = Zone.compare fd1.data fd2.data in - if c <> 0 then c - else Zone.compare fd1.indirect fd2.indirect - - let equal = Datatype.from_compare - - let pretty fmt d = Zone.pretty fmt (to_zone d) - - let reprs = - List.map (fun z -> {data = z; indirect = z}) Zone.reprs - - let structural_descr = - Structural_descr.t_record [| Zone.packed_descr; Zone.packed_descr; |] - let rehash = Datatype.identity - - let mem_project = Datatype.never_any_project - - let copy = Datatype.undefined - end) - - include DatatypeFromDeps - - let pretty_precise fmt {data; indirect} = - let bottom_data = Zone.is_bottom data in - let bottom_indirect = Zone.is_bottom indirect in - match bottom_indirect, bottom_data with - | true, true -> - Format.fprintf fmt "\\nothing" - | true, false -> - Format.fprintf fmt "direct: %a" - Zone.pretty data - | false, true -> - Format.fprintf fmt "indirect: %a" - Zone.pretty indirect - | false, false -> - Format.fprintf fmt "indirect: %a; direct: %a" - Zone.pretty indirect - Zone.pretty data - - let from_data_deps z = { data = z; indirect = Zone.bottom } - let from_indirect_deps z = { data = Zone.bottom; indirect = z } - - let bottom = { - data = Zone.bottom; - indirect = Zone.bottom; - } - - let top = { - data = Zone.top; - indirect = Zone.top; - } - - let is_included fd1 fd2 = - Zone.is_included fd1.data fd2.data && - Zone.is_included fd1.indirect fd2.indirect - - let join fd1 fd2 = - if fd1 == bottom then fd2 - else if fd2 == bottom then fd1 - else { - data = Zone.join fd1.data fd2.data; - indirect = Zone.join fd1.indirect fd2.indirect - } - - let narrow fd1 fd2 = { - data = Zone.narrow fd1.data fd2.data; - indirect = Zone.narrow fd1.indirect fd2.indirect - } - - let add_data_dep fd data = - { fd with data = Zone.join fd.data data } - - let add_indirect_dep fd indirect = - { fd with indirect = Zone.join fd.indirect indirect } - - let map f fd = { - data = f fd.data; - indirect = f fd.indirect; - } - -end - module DepsOrUnassigned = struct type deps_or_unassigned = @@ -310,7 +209,7 @@ module Memory = struct (** Once the base is known, we can obtain something of type [Deps.t] *) let convert_find_offsm base fp = let z = Zone.inject base fp.fo_itvs in - Deps.add_data_dep fp.fo_deps z + Deps.add_data fp.fo_deps z let empty_find_offsm = { fo_itvs = Int_Intervals.bottom; @@ -354,7 +253,7 @@ module Memory = struct let conv = convert_find_offsm in (* We are querying a zone for which no dependency is stored. Hence, every base is implicitly bound to [Unassigned]. *) - let empty_map z = Deps.from_data_deps z in + let empty_map z = Deps.data z in let join = Deps.join in let empty = Deps.bottom in (* Partial application is important *) @@ -418,7 +317,7 @@ module Memory = struct does the recursive descent. *) let substitute_data_deps = (* Nothing left to substitute, return z unchanged *) - let empty_right z = Deps.from_data_deps z in + let empty_right z = Deps.data z in (* Zone to substitute is empty *) let empty_left _ = Deps.bottom in (* [b] is in the zone and substituted. Rewrite appropriately *) @@ -505,7 +404,7 @@ module Memory = struct end -type froms = +type t = { deps_return : Memory.return; deps_table : Memory.t } @@ -600,31 +499,33 @@ let equal { deps_return = dr' ; deps_table = dt' } = Memory.equal dt dt'&& Deps.equal dr dr' -include Datatype.Make - (struct - type t = froms - let reprs = - List.fold_left - (fun acc o -> - List.fold_left - (fun acc m -> { deps_return = o; deps_table = m } :: acc) - acc - Memory.reprs) - [] - Deps.reprs - let structural_descr = - Structural_descr.t_record - [| Deps.packed_descr; - Memory.packed_descr |] - let name = "Function_Froms" - let hash = hash - let compare = Datatype.undefined - let equal = equal - let pretty = pretty - let rehash = Datatype.identity - let copy = Datatype.undefined - let mem_project = Datatype.never_any_project - end) +include + (Datatype.Make + (struct + type nonrec t = t + let reprs = + List.fold_left + (fun acc o -> + List.fold_left + (fun acc m -> { deps_return = o; deps_table = m } :: acc) + acc + Memory.reprs) + [] + Deps.reprs + let structural_descr = + Structural_descr.t_record + [| Deps.packed_descr; + Memory.packed_descr |] + let name = "Function_Froms" + let hash = hash + let compare = Datatype.undefined + let equal = equal + let pretty = pretty + let rehash = Datatype.identity + let copy = Datatype.undefined + let mem_project = Datatype.never_any_project + end) + : Datatype.S with type t := t) (* Local Variables: diff --git a/src/kernel_services/abstract_interp/function_Froms.mli b/src/plugins/eva/types/froms.mli similarity index 85% rename from src/kernel_services/abstract_interp/function_Froms.mli rename to src/plugins/eva/types/froms.mli index 141bfc5f9a5266c16d87476242410a5f7f679f83..b90b41363da6acbdb0d9e5704471375c5045dc28 100644 --- a/src/kernel_services/abstract_interp/function_Froms.mli +++ b/src/plugins/eva/types/froms.mli @@ -22,34 +22,7 @@ (** Datastructures and common operations for the results of the From plugin. *) -module Deps : sig - - type deps = { - data: Locations.Zone.t; - indirect: Locations.Zone.t; - } - - val bottom: deps - val top: deps - val is_included: deps -> deps -> bool - val join: deps -> deps -> deps - val narrow: deps -> deps -> deps - val to_zone: deps -> Locations.Zone.t - - val add_data_dep: deps -> Locations.Zone.t -> deps - val add_indirect_dep: deps -> Locations.Zone.t -> deps - - - val from_data_deps: Locations.Zone.t -> deps - val from_indirect_deps: Locations.Zone.t -> deps - - val map: (Locations.Zone.t -> Locations.Zone.t) -> deps -> deps - - include Datatype.S with type t = deps - - val pretty_precise : Format.formatter -> t -> unit -end - +[@@@ api_start] module DepsOrUnassigned : sig @@ -85,7 +58,7 @@ module DepsOrUnassigned : sig val pretty_precise : Format.formatter -> t -> unit val to_zone: t -> Locations.Zone.t - val to_deps: t -> Deps.deps + val to_deps: t -> Deps.t end module Memory : sig @@ -149,35 +122,37 @@ end -type froms = { +type t = { deps_return : Memory.return (** Dependencies for the returned value *); deps_table : Memory.t (** Dependencies on all the zones modified by the function *); } -include Datatype.S with type t = froms +include Datatype.S with type t := t -val join: froms -> froms -> froms +val join: t -> t -> t -val top: froms +val top: t (** Display dependencies of a function, using the function's type to improve readability *) -val pretty_with_type: Cil_types.typ -> froms Pretty_utils.formatter +val pretty_with_type: Cil_types.typ -> t Pretty_utils.formatter (** Display dependencies of a function, using the function's type to improve readability, separating direct and indirect dependencies *) -val pretty_with_type_indirect: Cil_types.typ -> froms Pretty_utils.formatter +val pretty_with_type_indirect: Cil_types.typ -> t Pretty_utils.formatter (** Extract the left part of a from result, ie. the zones that are written *) -val outputs: froms -> Locations.Zone.t +val outputs: t -> Locations.Zone.t (** Extract the right part of a from result, ie. the zones on which the written zones depend. If [include_self] is true, and the from is of the form [x FROM y (and SELF)], [x] is added to the result; default value is [false]. *) -val inputs: ?include_self:bool -> froms -> Locations.Zone.t +val inputs: ?include_self:bool -> t -> Locations.Zone.t + +[@@@ api_end] (* Local Variables: diff --git a/src/plugins/eva/utils/cvalue_callbacks.ml b/src/plugins/eva/utils/cvalue_callbacks.ml index d4101a12b9c2de6f3a289deef62458ba3a3ef6c6..66b713cce3ab8097787ba1864d1782049ea2cb57 100644 --- a/src/plugins/eva/utils/cvalue_callbacks.ml +++ b/src/plugins/eva/utils/cvalue_callbacks.ml @@ -41,7 +41,7 @@ let register_call_hook f = let apply_call_hooks callstack kf state kind = Call.apply (callstack, kf, state, kind) -type call_froms = (Function_Froms.froms * Locations.Zone.t) option +type call_froms = (Froms.t * Locations.Zone.t) option type state_by_stmt = (state Cil_datatype.Stmt.Hashtbl.t) Lazy.t type results = { before_stmts: state_by_stmt; after_stmts: state_by_stmt } diff --git a/src/plugins/eva/utils/cvalue_callbacks.mli b/src/plugins/eva/utils/cvalue_callbacks.mli index baa6dc0942ac19de3ec39a0ce11584b893626fe8..d48fb793c6b79cbc0ea96f37d6d9cad43c1c6040 100644 --- a/src/plugins/eva/utils/cvalue_callbacks.mli +++ b/src/plugins/eva/utils/cvalue_callbacks.mli @@ -33,7 +33,7 @@ type state = Cvalue.Model.t (** If not None, the froms of the function, and its sure outputs; i.e. the dependencies of the result, and the dependencies of each zone written to. *) -type call_froms = (Function_Froms.froms * Locations.Zone.t) option +type call_froms = (Froms.t * Locations.Zone.t) option type analysis_kind = [ `Builtin (** A cvalue builtin is used to interpret the function. *) diff --git a/src/plugins/eva/utils/private.ml b/src/plugins/eva/utils/private.ml index e4a368655a9c996dcafcb0369e4ba346cfa6549b..564056180ee41b2d2b1173113daeb53e2075a37b 100644 --- a/src/plugins/eva/utils/private.ml +++ b/src/plugins/eva/utils/private.ml @@ -40,6 +40,7 @@ module Eval_annots = Eval_annots module Eval_op = Eval_op module Eval_terms = Eval_terms module Eval_typ = Eval_typ +module Froms = Froms module Function_calls = Function_calls module Logic_inout = Logic_inout module Main_locations = Main_locations diff --git a/src/plugins/eva/utils/private.mli b/src/plugins/eva/utils/private.mli index f70377152869169e4763bef80aca6d553384f555..1a614467fd16d849f0091a1781d113ce5219a8d8 100644 --- a/src/plugins/eva/utils/private.mli +++ b/src/plugins/eva/utils/private.mli @@ -44,6 +44,7 @@ module Eval_annots = Eval_annots module Eval_op = Eval_op module Eval_terms = Eval_terms module Eval_typ = Eval_typ +module Froms = Froms module Function_calls = Function_calls module Logic_inout = Logic_inout module Main_locations = Main_locations diff --git a/src/plugins/from/From.ml b/src/plugins/from/From.ml index 03c99df40462fd32d23c0c3d9794b283fc074559..4073b6e66775afbb55bd718bfb42b3b8b4a33c49 100644 --- a/src/plugins/from/From.ml +++ b/src/plugins/from/From.ml @@ -27,7 +27,7 @@ let is_computed = Functionwise.is_computed let get = Functionwise.get let pretty = Functionwise.pretty -let access zone mem = Function_Froms.Memory.find mem zone +let access zone mem = Eva.Froms.Memory.find mem zone let display fmt = From_register.display (Some fmt) diff --git a/src/plugins/from/From.mli b/src/plugins/from/From.mli index ac8e62ad0c26771c22e8f1ccf023d03be617a62f..dfc0e8c32390c22edba090136edc55fdeec0bee5 100644 --- a/src/plugins/from/From.mli +++ b/src/plugins/from/From.mli @@ -28,8 +28,8 @@ val is_computed : kernel_function -> bool val compute : kernel_function -> unit val compute_all : unit -> unit -val get : Cil_types.kernel_function -> Function_Froms.froms -val access : Locations.Zone.t -> Function_Froms.Memory.t -> Locations.Zone.t +val get : Cil_types.kernel_function -> Eva.Froms.t +val access : Locations.Zone.t -> Eva.Froms.Memory.t -> Locations.Zone.t val self : State.t @@ -42,6 +42,6 @@ val display : Format.formatter -> unit val compute_all_calldeps : unit -> unit module Callwise : sig - val iter : (Cil_types.kinstr -> Function_Froms.froms -> unit) -> unit - val find : Cil_types.kinstr -> Function_Froms.froms + val iter : (Cil_types.kinstr -> Eva.Froms.t -> unit) -> unit + val find : Cil_types.kinstr -> Eva.Froms.t end diff --git a/src/plugins/from/callwise.ml b/src/plugins/from/callwise.ml index 0e5d37b4d35d0d8aaf6bd1613548ee7cd526d7d2..d909206a8493e0e8c078625e8bc4d42b02946187 100644 --- a/src/plugins/from/callwise.ml +++ b/src/plugins/from/callwise.ml @@ -25,7 +25,7 @@ open Cil_datatype module Tbl = Cil_state_builder.Kinstr_hashtbl - (Function_Froms) + (Eva.Froms) (struct let name = "Callwise dependencies" let size = 17 @@ -36,7 +36,7 @@ let () = From_parameters.ForceCallDeps.set_output_dependencies [Tbl.self] let merge_call_froms table callsite froms = try let current = Kinstr.Hashtbl.find table callsite in - let new_froms = Function_Froms.join froms current in + let new_froms = Eva.Froms.join froms current in Kinstr.Hashtbl.replace table callsite new_froms with Not_found -> Kinstr.Hashtbl.add table callsite froms @@ -44,7 +44,7 @@ let merge_call_froms table callsite froms = (** State for the analysis of one function call *) type from_state = { current_function: Kernel_function.t (** Function being analyzed *); - table_for_calls: Function_Froms.t Kinstr.Hashtbl.t + table_for_calls: Eva.Froms.t Kinstr.Hashtbl.t (** State of the From plugin for each statement containing a function call in the body of [current_function]. Updated incrementally each time Value analyses such a statement *); @@ -59,7 +59,7 @@ let call_froms_stack : from_state list ref = ref [] let record_callwise_dependencies_in_db call_site froms = try let previous = Tbl.find call_site in - Tbl.replace call_site (Function_Froms.join previous froms) + Tbl.replace call_site (Eva.Froms.join previous froms) with Not_found -> Tbl.add call_site froms let call_for_individual_froms _callstack current_function _state call_type = @@ -97,7 +97,7 @@ let end_record callstack froms = module MemExec = State_builder.Hashtbl (Datatype.Int.Hashtbl) - (Function_Froms) + (Eva.Froms) (struct let size = 17 let dependencies = [Tbl.self] @@ -135,7 +135,7 @@ let record_for_individual_froms callstack kf pre_state value_res = let froms = if Eva.Analysis.save_results kf then compute_call_from_value_states kf (Lazy.force before_stmts) - else Function_Froms.top + else Eva.Froms.top in if From_parameters.VerifyAssigns.get () then Eva.Logic_inout.verify_assigns kf ~pre:pre_state froms; diff --git a/src/plugins/from/callwise.mli b/src/plugins/from/callwise.mli index 6fa25e4f741c7f6803d63cdfd1795f81423afdee..2cdb2cb3e7ddbda80336cd881940a84ef65d52bd 100644 --- a/src/plugins/from/callwise.mli +++ b/src/plugins/from/callwise.mli @@ -25,5 +25,5 @@ precise than the functionwise results. *) val compute_all_calldeps : unit -> unit -val iter : (Cil_types.kinstr -> Function_Froms.froms -> unit) -> unit -val find : Cil_types.kinstr -> Function_Froms.froms +val iter : (Cil_types.kinstr -> Eva.Froms.t -> unit) -> unit +val find : Cil_types.kinstr -> Eva.Froms.t diff --git a/src/plugins/from/from_compute.ml b/src/plugins/from/from_compute.ml index 4c662872580ba2732f0583f403dda70ffe646c7a..f9668845e4102fe41b0da3e82f972881ed477d43 100644 --- a/src/plugins/from/from_compute.ml +++ b/src/plugins/from/from_compute.ml @@ -33,16 +33,16 @@ module Record_From_Callbacks = (struct type t = (Kernel_function.t Stack.t) * - Function_Froms.Memory.t Stmt.Hashtbl.t * - (Kernel_function.t * Function_Froms.Memory.t) list Stmt.Hashtbl.t + Eva.Froms.Memory.t Stmt.Hashtbl.t * + (Kernel_function.t * Eva.Froms.Memory.t) list Stmt.Hashtbl.t end) module type To_Use = sig - val get_from_call : kernel_function -> stmt -> Function_Froms.t + val get_from_call : kernel_function -> stmt -> Eva.Froms.t val stmt_request : stmt -> Eva.Results.request val keep_base : kernel_function -> Base.t -> bool - val cleanup_and_save : kernel_function -> Function_Froms.t -> Function_Froms.t + val cleanup_and_save : kernel_function -> Eva.Froms.t -> Eva.Froms.t end let compute_using_prototype_for_state state kf assigns = @@ -53,7 +53,7 @@ let compute_using_prototype_for_state state kf assigns = From_parameters.warning "@[no assigns clauses@ for function %a.@]@ \ Results will be imprecise." Kernel_function.pretty kf; - Function_Froms.Memory.(top_return, top) + Eva.Froms.Memory.(top_return, top) | Writes assigns -> let (rt_typ,_,_,_) = splitFunctionTypeVI varinfo in let input_zone out ins = @@ -75,9 +75,9 @@ let compute_using_prototype_for_state state kf assigns = (* assign clauses do not let us specify address dependencies for now, so we assume it is all data dependencies *) - let input_deps = Function_Froms.Deps.from_data_deps input_zone in + let input_deps = Eva.Deps.data input_zone in (* Weak update of the over-approximation of the zones assigned *) - let acc = Function_Froms.Memory.add_binding ~exact:false + let acc = Eva.Froms.Memory.add_binding ~exact:false acc output.over input_deps in (* Now, perform a strong update on the zones that are guaranteed to be assigned (under-approximation) AND that do not depend @@ -90,7 +90,7 @@ let compute_using_prototype_for_state state kf assigns = Zone.(if equal top input_zone then bottom else diff output.under input_zone) in - let acc = Function_Froms.Memory.add_binding ~exact:true + let acc = Eva.Froms.Memory.add_binding ~exact:true acc sure_out_zone input_deps in acc @@ -99,15 +99,15 @@ let compute_using_prototype_for_state state kf assigns = let zone_from = input_zone out from in (* assign clauses do not let us specify address dependencies for now, so we assume it is all data dependencies *) - let inputs_deps = Function_Froms.Deps.from_data_deps zone_from in + let inputs_deps = Eva.Deps.data zone_from in try let coffs = Logic_to_c.loc_to_offset out.it_content in List.fold_left (fun acc coff -> let (base,width) = bitsOffset rt_typ coff in let size = Int_Base.inject (Int.of_int width) in - Function_Froms.Memory.(add_to_return - ~start:base ~size ~m:acc inputs_deps) + Eva.Froms.Memory.add_to_return + ~start:base ~size ~m:acc inputs_deps ) acc coffs with Logic_to_c.No_conversion | SizeOfError _ -> @@ -115,7 +115,7 @@ let compute_using_prototype_for_state state kf assigns = "Unable to extract a proper offset. \ Using FROM for the whole \\result"; let size = Bit_utils.sizeof rt_typ in - Function_Froms.(Memory.add_to_return ~size ~m:acc inputs_deps) + Eva.Froms.Memory.add_to_return ~size ~m:acc inputs_deps in let return_assigns, other_assigns = List.fold_left @@ -127,19 +127,19 @@ let compute_using_prototype_for_state state kf assigns = let return_assigns = match return_assigns with | [] when Cil.isVoidType rt_typ -> - Function_Froms.Memory.default_return + Eva.Froms.Memory.default_return | [] -> (* \from unspecified. *) let size = Bit_utils.sizeof rt_typ in - Function_Froms.Memory.top_return_size size + Eva.Froms.Memory.top_return_size size | _ -> List.fold_left treat_ret_assign - Function_Froms.Memory.default_return return_assigns + Eva.Froms.Memory.default_return return_assigns in return_assigns, List.fold_left - treat_assign Function_Froms.Memory.empty other_assigns + treat_assign Eva.Froms.Memory.empty other_assigns in - { deps_return = return_deps; Function_Froms.deps_table = deps } + Eva.Froms.{ deps_return = return_deps; deps_table = deps } module ZoneStmtMap = struct include @@ -164,7 +164,7 @@ struct the statement that gave rise to the dependency. *) additional_deps : Zone.t; (** Union of the sets in {!additional_deps_table} *) - deps_table : Function_Froms.Memory.t + deps_table : Eva.Froms.Memory.t (** dependency table *) } @@ -181,7 +181,7 @@ struct depending directly on an indirect dependency -> indirect, depending indirectly on a direct dependency -> indirect *) let merge_deps f deps = - let open Function_Froms.Deps in + let open Eva.Deps in let ind = f deps.indirect in let data = f deps.data in let ind = Zone.join data.indirect (to_zone ind) in @@ -202,7 +202,7 @@ struct let aux_local acc vi = Cil.CurrentLoc.set vi.vdecl; (* Consider that local are initialized to a constant value *) - Function_Froms.Memory.bind_var vi Function_Froms.Deps.bottom acc + Eva.Froms.Memory.bind_var vi Eva.Deps.bottom acc in let loc = Cil.CurrentLoc.get () in @@ -212,7 +212,7 @@ struct let unbind_locals m b = let aux_local acc vi = - Function_Froms.Memory.unbind_var vi acc + Eva.Froms.Memory.unbind_var vi acc in List.fold_left aux_local m b.blocals @@ -221,7 +221,7 @@ struct let request = To_Use.stmt_request stmt in let pre_trans = Eva.Results.expr_dependencies expr request in merge_deps - (fun d -> Function_Froms.Memory.find_precise deps_tbl d) pre_trans + (fun d -> Eva.Froms.Memory.find_precise deps_tbl d) pre_trans let lval_to_zone_with_deps stmt lv = let request = To_Use.stmt_request stmt in @@ -238,12 +238,12 @@ struct let empty_from = { additional_deps_table = ZoneStmtMap.empty; additional_deps = Zone.bottom; - deps_table = Function_Froms.Memory.empty } + deps_table = Eva.Froms.Memory.empty } let bottom_from = { additional_deps_table = ZoneStmtMap.empty; additional_deps = Zone.bottom; - deps_table = Function_Froms.Memory.bottom } + deps_table = Eva.Froms.Memory.bottom } module Computer = struct @@ -253,11 +253,11 @@ struct let callwise_states_with_formals = Stmt.Hashtbl.create 7 let substitute call_site_froms extra_loc deps = - let subst_deps = Function_Froms.Memory.substitute call_site_froms deps in - Function_Froms.Deps.add_indirect_dep subst_deps extra_loc + let subst_deps = Eva.Froms.Memory.substitute call_site_froms deps in + Eva.Deps.add_indirect subst_deps extra_loc let display_one_from fmt v = - Function_Froms.Memory.pretty fmt v.deps_table; + Eva.Froms.Memory.pretty fmt v.deps_table; Format.fprintf fmt "Additional Variable Map : %a@\n" ZoneStmtMap.pretty v.additional_deps_table; Format.fprintf fmt @@ -270,7 +270,7 @@ struct let transfer_conditional_exp s exp state = let additional = find s state.deps_table exp in - let additional = Function_Froms.Deps.to_zone additional in + let additional = Eva.Deps.to_zone additional in {state with additional_deps_table = ZoneStmtMap.add s additional state.additional_deps_table; @@ -291,10 +291,10 @@ struct m, new_z, false in let map = - Function_Froms.Memory.join new_.deps_table old.deps_table + Eva.Froms.Memory.join new_.deps_table old.deps_table in let included' = - Function_Froms.Memory.is_included new_.deps_table old.deps_table + Eva.Froms.Memory.is_included new_.deps_table old.deps_table in { deps_table = map; additional_deps_table = additional_map; @@ -314,12 +314,12 @@ struct let deps, loc, exact = lval_to_precise_loc_with_deps stmt ~for_writing:(not init) lv in - let deps_of_deps = Function_Froms.Memory.find state.deps_table deps in + let deps_of_deps = Eva.Froms.Memory.find state.deps_table deps in let all_indirect = Zone.join state.additional_deps deps_of_deps in - let deps = Function_Froms.Deps.add_indirect_dep deps_right all_indirect in + let deps = Eva.Deps.add_indirect deps_right all_indirect in let access = if init then Read else Write in { state with deps_table = - Function_Froms.Memory.add_binding_precise_loc + Eva.Froms.Memory.add_binding_precise_loc ~exact access state.deps_table loc deps } let transfer_call stmt dest f args _loc state = @@ -328,9 +328,7 @@ struct let called_vinfos = Eva.Results.(eval_callee f request |> default []) in let f_deps = Eva.Results.expr_deps f request in (* dependencies for the evaluation of [f] *) - let f_deps = - Function_Froms.Memory.find state.deps_table f_deps - in + let f_deps = Eva.Froms.Memory.find state.deps_table f_deps in let additional_deps = Zone.join state.additional_deps @@ -350,8 +348,8 @@ struct state else let froms_call = To_Use.get_from_call kf stmt in - let froms_call_table = froms_call.Function_Froms.deps_table in - if Function_Froms.Memory.is_bottom froms_call_table then + let froms_call_table = froms_call.Eva.Froms.deps_table in + if Eva.Froms.Memory.is_bottom froms_call_table then bottom_from else let formal_args = Kernel_function.get_formals kf in @@ -360,7 +358,7 @@ struct List.iter2 (fun vi from -> state_with_formals := - Function_Froms.Memory.bind_var + Eva.Froms.Memory.bind_var vi from !state_with_formals; ) formal_args args_froms; with Invalid_argument _ -> @@ -381,7 +379,7 @@ struct but before the result assignment *) let deps_after_call = let before_call = state.deps_table in - let open Function_Froms in + let open Eva.Froms in let subst d = DepsOrUnassigned.subst subst_before_call d in let call_substituted = Memory.map subst froms_call_table in Memory.compose call_substituted before_call @@ -392,7 +390,7 @@ struct match dest with | None -> state | Some lv -> - let return_from = froms_call.Function_Froms.deps_return in + let return_from = froms_call.Eva.Froms.deps_return in let deps_ret = subst_before_call return_from in let init = Cil.is_mutable_or_initialized lv in transfer_assign stmt ~init lv deps_ret state @@ -404,7 +402,7 @@ struct | Some acc_memory -> Some {state with - deps_table = Function_Froms.Memory.join + deps_table = Eva.Froms.Memory.join p.deps_table acc_memory.deps_table} in @@ -452,7 +450,7 @@ struct (* If implicit zero-initializers have been skipped, also mark the entire array as initialized from no dependency (nothing is read by the implicit zero-initializers). *) - transfer_assign stmt ~init:true lv Function_Froms.Deps.bottom r + transfer_assign stmt ~init:true lv Eva.Deps.bottom r in aux (Cil.var v) i state | Call (lvaloption,funcexp,argl,loc) -> @@ -521,7 +519,7 @@ struct (* Filter out unreachable values. *) let transfer_stmt s d = if Eva.Results.is_reachable s && - not (Function_Froms.Memory.is_bottom d.deps_table) + not (Eva.Froms.Memory.is_bottom d.deps_table) then transfer_stmt s d else [] @@ -552,25 +550,25 @@ struct (match return.skind with | Return (Some ({enode = Lval v}),_) -> let zone = lval_to_zone_with_deps return v in - let deps = Function_Froms.Memory.find_precise state.deps_table zone in + let deps = Eva.Froms.Memory.find_precise state.deps_table zone in let size = Bit_utils.sizeof (Cil.typeOfLval v) in - Function_Froms.(Memory.add_to_return ~size deps) + Eva.Froms.Memory.add_to_return ~size deps | Return (None,_) -> - Function_Froms.Memory.default_return + Eva.Froms.Memory.default_return | _ -> assert false) in let accept = To_Use.keep_base kf in let deps_table = - Function_Froms.Memory.filter_base accept state.deps_table + Eva.Froms.Memory.filter_base accept state.deps_table in - { deps_return = deps_return; - Function_Froms.deps_table = deps_table } + Eva.Froms.{ deps_return = deps_return; + deps_table = deps_table } let compute_using_cfg kf = match kf.fundec with | Declaration _ -> assert false | Definition (f,_) -> - if not (Eva.Analysis.save_results kf) then Function_Froms.top + if not (Eva.Analysis.save_results kf) then Eva.Froms.top else try Stack.iter (fun g -> if kf == g then raise Exit) call_stack; @@ -615,16 +613,15 @@ struct From_parameters.result "Non-terminating function %a (no dependencies)" Kernel_function.pretty kf; - { Function_Froms.deps_return = - Function_Froms.Memory.default_return; - deps_table = Function_Froms.Memory.bottom } + Eva.Froms.{ deps_return = Eva.Froms.Memory.default_return; + deps_table = Eva.Froms.Memory.bottom } end in last_from with Exit (* Recursive call *) -> - { Function_Froms.deps_return = Function_Froms.Memory.default_return; - deps_table = Function_Froms.Memory.empty } + { deps_return = Eva.Froms.Memory.default_return; + deps_table = Eva.Froms.Memory.empty } let compute_using_prototype kf = let state = Eva.Results.(at_start_of kf |> get_cvalue_model) in diff --git a/src/plugins/from/from_compute.mli b/src/plugins/from/from_compute.mli index 9beabb6c488608a4c1efd485a7b0d775dbff2859..2d9f43e4bb4b8d705098e97d1915feff95e8f00c 100644 --- a/src/plugins/from/from_compute.mli +++ b/src/plugins/from/from_compute.mli @@ -30,7 +30,7 @@ open Cil_types module type To_Use = sig (** How to find the Froms for a given call during the analysis. *) - val get_from_call : kernel_function -> stmt -> Function_Froms.t + val get_from_call : kernel_function -> stmt -> Eva.Froms.t (** The Eva request that can be used to evaluate expressions at a given statement through the Eva public API. *) @@ -43,7 +43,7 @@ sig (** Clean the given from (that have been computed for the given function), optionally save them, and return the cleaned result. *) - val cleanup_and_save : kernel_function -> Function_Froms.t -> Function_Froms.t + val cleanup_and_save : kernel_function -> Eva.Froms.t -> Eva.Froms.t end (** Function that compute the Froms from a given prototype, called @@ -52,14 +52,14 @@ val compute_using_prototype_for_state : Cvalue.Model.t -> Kernel_function.t -> assigns -> - Function_Froms.froms + Eva.Froms.t (** Functor computing the functional dependencies, according to the three modules above. *) module Make (_: To_Use) : sig (** Compute the dependencies of the given function, and return them *) - val compute_and_return : Kernel_function.t -> Function_Froms.t + val compute_and_return : Kernel_function.t -> Eva.Froms.t (** Compute the dependencies of the given function *) val compute : Kernel_function.t -> unit diff --git a/src/plugins/from/from_register.ml b/src/plugins/from/from_register.ml index df9beea20f8bd31766c25136d413db7fb06a2b9f..1ad6000d2d117c58b8d996fa7564e2649b75f939 100644 --- a/src/plugins/from/from_register.ml +++ b/src/plugins/from/from_register.ml @@ -24,7 +24,7 @@ open Cil_types let pretty_with_indirect fmt v = let deps = Functionwise.get v in - Function_Froms.pretty_with_type_indirect (Kernel_function.get_type v) fmt deps + Eva.Froms.pretty_with_type_indirect (Kernel_function.get_type v) fmt deps let display fmtopt = Option.iter (fun fmt -> Format.fprintf fmt "@[<v>") fmtopt; @@ -138,8 +138,8 @@ let print_calldeps () = From_parameters.printf ~header "@[ %a@]" ((if From_parameters.ShowIndirectDeps.get () - then Function_Froms.pretty_with_type_indirect - else Function_Froms.pretty_with_type) typ) + then Eva.Froms.pretty_with_type_indirect + else Eva.Froms.pretty_with_type) typ) d); From_parameters.feedback "====== END OF CALLWISE DEPENDENCIES ======" diff --git a/src/plugins/from/functionwise.ml b/src/plugins/from/functionwise.ml index 484fbdba5b54ddcd4643bbba1f7f7e62d396d3e6..91991c3ccc1d32a82652223613812edd92496fea 100644 --- a/src/plugins/from/functionwise.ml +++ b/src/plugins/from/functionwise.ml @@ -25,7 +25,7 @@ open Locations module Tbl = Kernel_function.Make_Table - (Function_Froms) + (Eva.Froms) (struct let name = "Functionwise dependencies" let size = 17 @@ -53,7 +53,7 @@ module To_Use = struct Eva.Logic_inout.accept_base ~formals:false ~locals:false kf let cleanup kf froms = - if Function_Froms.Memory.is_bottom froms.Function_Froms.deps_table + if Eva.Froms.Memory.is_bottom froms.Eva.Froms.deps_table then froms else let accept_base = @@ -75,11 +75,10 @@ module To_Use = struct zone_substitution x with Abstract_interp.Error_Top -> Zone.top in - let map_zone = Function_Froms.Deps.map zone_substitution in - let subst = Function_Froms.DepsOrUnassigned.subst map_zone in - let open Function_Froms in - { deps_table = Memory.map subst froms.deps_table; - deps_return = Deps.map zone_substitution froms.deps_return; + let map_zone = Eva.Deps.map zone_substitution in + let subst = Eva.Froms.DepsOrUnassigned.subst map_zone in + { deps_table = Eva.Froms.Memory.map subst froms.deps_table; + deps_return = Eva.Deps.map zone_substitution froms.deps_return; } let cleanup_and_save kf froms = @@ -111,7 +110,7 @@ let is_computed = Tbl.mem let get = To_Use.memo let pretty fmt v = - Function_Froms.pretty_with_type (Kernel_function.get_type v) fmt (get v) + Eva.Froms.pretty_with_type (Kernel_function.get_type v) fmt (get v) (* Local Variables: diff --git a/src/plugins/from/functionwise.mli b/src/plugins/from/functionwise.mli index 2f81e01120c45eb4fb58e1d242dd885c6f760136..aee21d2668d2b74d8e9090a1c16eabf71f305441 100644 --- a/src/plugins/from/functionwise.mli +++ b/src/plugins/from/functionwise.mli @@ -29,5 +29,5 @@ val self : State.t val compute : kernel_function -> unit val compute_all : unit -> unit val is_computed : kernel_function -> bool -val get : Cil_types.kernel_function -> Function_Froms.froms +val get : Cil_types.kernel_function -> Eva.Froms.t val pretty : Format.formatter -> kernel_function -> unit diff --git a/src/plugins/inout/operational_inputs.ml b/src/plugins/inout/operational_inputs.ml index d12bc75efab318688cbc438b023c28003b81d836..03c8aca99b100baf8c42109d3bb206f14e24fa07 100644 --- a/src/plugins/inout/operational_inputs.ml +++ b/src/plugins/inout/operational_inputs.ml @@ -515,25 +515,23 @@ let get_external_aux ?stmt kf = else !ref_get_external kf let extract_inout_from_froms froms = - let open Function_Froms in - let {deps_return; deps_table } = froms in - let in_return = Deps.to_zone deps_return in + let Eva.Froms.{ deps_return; deps_table } = froms in + let in_return = Eva.Deps.to_zone deps_return in let in_, out_ = match deps_table with - | Memory.Top -> Zone.top, Zone.top - | Memory.Bottom -> Zone.bottom, Zone.bottom - | Memory.Map m -> + | Top -> Zone.top, Zone.top + | Bottom -> Zone.bottom, Zone.bottom + | Map m -> let aux_from out in_ (acc_in,acc_out as acc) = - let open DepsOrUnassigned in (* Skip zones fully unassigned, they are not really port of the dependencies, but just present in the offsetmap to avoid "holes" *) - match in_ with + match (in_ : Eva.Froms.DepsOrUnassigned.t) with | DepsBottom | Unassigned -> acc | AssignedFrom in_ | MaybeAssignedFrom in_ -> - Zone.join acc_in (Deps.to_zone in_), + Zone.join acc_in (Eva.Deps.to_zone in_), Zone.join acc_out out in - Memory.fold aux_from m (Zone.bottom, Zone.bottom) + Eva.Froms.Memory.fold aux_from m (Zone.bottom, Zone.bottom) in (Zone.join in_return in_), out_ diff --git a/src/plugins/pdg/build.ml b/src/plugins/pdg/build.ml index 6db271d345e2405a1761dc0f0ea9be74ad26a0d8..3fb17f29435fdf84a85e684d9e8be70c5448a377 100644 --- a/src/plugins/pdg/build.ml +++ b/src/plugins/pdg/build.ml @@ -566,7 +566,7 @@ let finalize_pdg pdg from_opt = (* TODO : also add the nodes for the other from ! *) let state = match last_state with Some s -> s | None -> assert false in let process_out out deps s = - let open Function_Froms.DepsOrUnassigned in + let open Eva.Froms.DepsOrUnassigned in if (equal Unassigned deps) then s else @@ -574,24 +574,24 @@ let finalize_pdg pdg from_opt = let default = may_be_unassigned deps in add_from pdg state s out (default, from_out) in - let from_table = froms.Function_Froms.deps_table in + let from_table = froms.Eva.Froms.deps_table in let new_state = - if Function_Froms.Memory.is_bottom from_table then + if Eva.Froms.Memory.is_bottom from_table then Pdg_state.bottom else let new_state = match from_table with - | Function_Froms.Memory.Top -> + | Top -> process_out - Locations.Zone.top Function_Froms.DepsOrUnassigned.top state - | Function_Froms.Memory.Map m -> - Function_Froms.Memory.fold_fuse_same process_out m state - | Function_Froms.Memory.Bottom -> assert false (* checked above *) + Locations.Zone.top Eva.Froms.DepsOrUnassigned.top state + | Map m -> + Eva.Froms.Memory.fold_fuse_same process_out m state + | Bottom -> assert false (* checked above *) in if not (Kernel_function.returns_void pdg.fct) then begin - let from0 = froms.Function_Froms.deps_return in - let deps_ret = Function_Froms.Memory.collapse_return from0 in - let deps_ret = Function_Froms.Deps.to_zone deps_ret in + let from0 = froms.Eva.Froms.deps_return in + let deps_ret = Eva.Froms.Memory.collapse_return from0 in + let deps_ret = Eva.Deps.to_zone deps_ret in ignore (create_fun_output_node pdg (Some new_state) deps_ret) end; @@ -651,46 +651,45 @@ let call_outputs pdg state_before_call state_with_inputs stmt lvaloption froms fct_dpds = (* obtain inputs from state_with_inputs to avoid mixing in and out *) - let froms_deps_return = froms.Function_Froms.deps_return in - let from_table = froms.Function_Froms.deps_table in + let froms_deps_return = froms.Eva.Froms.deps_return in + let from_table = froms.Eva.Froms.deps_table in let print_outputs fmt = Format.fprintf fmt "call outputs : %a" - Function_Froms.Memory.pretty from_table; + Eva.Froms.Memory.pretty from_table; if not (lvaloption = None) then Format.fprintf fmt "\t and \\result %a@." - Function_Froms.Deps.pretty froms_deps_return + Eva.Deps.pretty froms_deps_return in debug "%t" print_outputs; let process_out out deps state = - if Function_Froms.DepsOrUnassigned.(equal Unassigned deps) then + if Eva.Froms.DepsOrUnassigned.(equal Unassigned deps) then state else - let from_out = Function_Froms.DepsOrUnassigned.to_zone deps in - let default = Function_Froms.DepsOrUnassigned.may_be_unassigned deps in + let from_out = Eva.Froms.DepsOrUnassigned.to_zone deps in + let default = Eva.Froms.DepsOrUnassigned.may_be_unassigned deps in process_call_output pdg state_with_inputs state stmt out default from_out fct_dpds in - if Function_Froms.Memory.is_bottom from_table then + if Eva.Froms.Memory.is_bottom from_table then Pdg_state.bottom else let state_with_outputs = - let open Function_Froms in match from_table with - | Memory.Top -> + | Top -> process_out - Locations.Zone.top DepsOrUnassigned.top state_before_call - | Memory.Bottom -> assert false (* checked above *) - | Memory.Map m -> - Memory.fold_fuse_same process_out m state_before_call + Locations.Zone.top Eva.Froms.DepsOrUnassigned.top state_before_call + | Bottom -> assert false (* checked above *) + | Map m -> + Eva.Froms.Memory.fold_fuse_same process_out m state_before_call in match lvaloption with | None -> state_with_outputs | Some lval -> let r_dpds = - Function_Froms.Memory.collapse_return froms_deps_return + Eva.Froms.Memory.collapse_return froms_deps_return in - let r_dpds = Function_Froms.Deps.to_zone r_dpds in + let r_dpds = Eva.Deps.to_zone r_dpds in let (l_loc, exact, l_dpds, l_decl) = get_lval_infos lval stmt in process_call_return pdg diff --git a/src/plugins/scope/zones.ml b/src/plugins/scope/zones.ml index 03a5d675411bf205295840b9b9102a57a8931f6f..3bf6e3bfd52905d30f1cdb0154ac410664a8b1fc 100644 --- a/src/plugins/scope/zones.ml +++ b/src/plugins/scope/zones.ml @@ -79,9 +79,9 @@ let process_call_res data stmt lvaloption froms = let data = match lvaloption with | None -> false, data | Some lval -> - let ret_dpds = froms.Function_Froms.deps_return in - let r_dpds = Function_Froms.Memory.collapse_return ret_dpds in - let r_dpds = Function_Froms.Deps.to_zone r_dpds in + let ret_dpds = froms.Eva.Froms.deps_return in + let r_dpds = Eva.Froms.Memory.collapse_return ret_dpds in + let r_dpds = Eva.Deps.to_zone r_dpds in let l_dpds, exact, l_zone = get_lval_zones ~for_writing:true stmt lval in compute_new_data data l_zone l_dpds exact r_dpds @@ -92,10 +92,10 @@ let process_call_res data stmt lvaloption froms = * Moreover, we need to add the part of [data_after] that has not been * modified for sure. *) let process_froms data_after froms = - let from_table = froms.Function_Froms.deps_table in + let from_table = froms.Eva.Froms.deps_table in let process_out_call out deps (to_prop, used, new_data) = - let out_dpds = Function_Froms.DepsOrUnassigned.to_zone deps in - let default = Function_Froms.DepsOrUnassigned.may_be_unassigned deps in + let out_dpds = Eva.Froms.DepsOrUnassigned.to_zone deps in + let default = Eva.Froms.DepsOrUnassigned.may_be_unassigned deps in let exact = not default in (* be careful to compare out with data_after and not new_data *) if (Data.intersects data_after out) then @@ -113,12 +113,12 @@ let process_froms data_after froms = let used = false in (* is the call needed ? *) let to_prop, used, new_data = match from_table with - | Function_Froms.Memory.Bottom -> to_prop, used, new_data - | Function_Froms.Memory.Top -> - let v = Function_Froms.DepsOrUnassigned.top in + | Bottom -> to_prop, used, new_data + | Top -> + let v = Eva.Froms.DepsOrUnassigned.top in process_out_call Locations.Zone.top v (to_prop, used, new_data) - | Function_Froms.Memory.Map m -> - Function_Froms.Memory.fold process_out_call m (to_prop, used, new_data) + | Map m -> + Eva.Froms.Memory.fold process_out_call m (to_prop, used, new_data) in let data = Data.merge to_prop new_data in (used, data)