From 0e685069f3f676939e0af77c3589e490df52c28e Mon Sep 17 00:00:00 2001 From: Maxime Jacquemin <maxime2.jacquemin@gmail.com> Date: Mon, 20 Feb 2023 18:56:31 +0100 Subject: [PATCH] [Eva] Abstractions: final steps to handle multiple locations. Abstractions.ml should be done; now we have to fix everything else (in the next commits). --- src/plugins/eva/engine/abstractions.ml | 870 ++++++------------------ src/plugins/eva/engine/abstractions.mli | 130 ++++ 2 files changed, 321 insertions(+), 679 deletions(-) diff --git a/src/plugins/eva/engine/abstractions.ml b/src/plugins/eva/engine/abstractions.ml index cf62ec9304b..20d2b3c3a4b 100644 --- a/src/plugins/eva/engine/abstractions.ml +++ b/src/plugins/eva/engine/abstractions.ml @@ -86,7 +86,6 @@ module Value = struct updating the structure. *) let add : type v. v registered -> structured -> structured = fun (key, input) structured -> - let open Abstract.Value in let module Interactive = (val make_interactive structured) in if not (Interactive.mem key) then (module struct @@ -99,13 +98,11 @@ module Value = struct (* The minimal value abstraction to use. It contains the CValue abstraction, configured depending of the bitwise *) - let init (is_bitwise : bool) : structured = - if not is_bitwise then - (module struct - include Main_values.CVal - let structure = Abstract.Value.Leaf (key, (module Main_values.CVal)) - end) - else (module Offsm_value.CvalueOffsm) + let init : structured = + (module struct + include Main_values.CVal + let structure = Abstract.Value.Leaf (key, (module Main_values.CVal)) + end) (* When building the complete abstraction, we need to trick locations and @@ -116,7 +113,6 @@ module Value = struct This functor is responsible of building such conversion operations. *) module type From = sig type value val structure : value structure end module Converter (From : From) (To : Interactive) = struct - type internal = From.value type extended = To.t let structure = From.structure @@ -207,6 +203,13 @@ module Location = struct | Last registered -> folder registered acc | hd :: tl -> fold { folder } tl (folder hd acc) + let rec fold_values : type v. 'a Value.folder -> v dependencies -> 'a -> 'a = + fun folder dependencies acc -> + match dependencies with + | Last (module R) -> Value.fold folder R.dependencies acc + | (module R) :: tl -> + fold_values folder tl (Value.fold folder R.dependencies acc) + (* As for the value abstraction, building the location abstraction consists of structuring the needed registered locations and then adding the needed @@ -229,30 +232,31 @@ module Location = struct type 'v structured = (module Structured with type value = 'v) type 'v interactive = (module Interactive with type value = 'v) - let init : type v. (module Value.Interactive with type t = v) -> v structured = - fun (module Interactive) -> - let module CVal = Main_values.CVal in - let leaf = Abstract.Value.Leaf (CVal.key, (module CVal)) in - let module From = struct type value = CVal.t let structure = leaf end in - let module Converter = Value.Converter (From) (Interactive) in - let module Loc = Location_lift.Make (Main_locations.PLoc) (Converter) in - (module struct - type value = v - module Value = Interactive - module Location = Loc - end) + (* Initial location builder *) + module Init (V : Value.Interactive) : Structured with type value = V.t = + struct + module CVal = Main_values.CVal + let leaf = Abstract.Value.Leaf (CVal.key, (module CVal)) + module From = struct type value = CVal.t let structure = leaf end + module Converter = Value.Converter (From) (V) + + type value = V.t + module Value = V + module Location = Location_lift.Make (Main_locations.PLoc) (Converter) + end (* Making a structured value interactive simply consists of adding the needed operations using the Structure.Open functor.*) - let make_interactive (module Structured : Structured) = - (module struct - include Structured.Location - include Structure.Open (Abstract.Location) (struct + let make_interactive : type v. v structured -> v interactive = + fun (module Structured) -> + (module struct include Structured.Location - type t = location + include Structure.Open (Abstract.Location) (struct + include Structured.Location + type t = location + end) end) - end : Interactive) (* Adding a registered location into a structured one is done in three steps: 1. Computing the values dependencies structure. @@ -303,7 +307,6 @@ module Location = struct responsible of building such conversion operations. *) module type From = sig type location val structure : location structure end module Converter (From : From) (To : Interactive) = struct - type internal = From.location type extended = To.location let structure = From.structure @@ -389,8 +392,12 @@ module Domain = struct <location>. *) module type Domain = sig type location - module Make (V : Value.Interactive) : - Abstract_domain.Leaf with type value = V.t and type location = location + module Make (V : Value.Interactive) : sig + include Abstract_domain.S + with type value = V.t + and type location = location + val key : state key + end end type 'l domain = (module Domain with type location = 'l) @@ -445,10 +452,40 @@ module Domain = struct | RegisteredDomain : 's Leaf.registered -> registered | RegisteredFunctor : Functor.registered -> registered - let register = function + type 't with_info = + { name : string + ; experimental : bool + ; priority : int + ; abstraction : 't + } + + type 't with_mode = 't * Domain_mode.t option + + + let static_domains = ref [] + let dynamic_domains = ref [] + + let register_domain_option ~name ~experimental ~descr = + let descr = if experimental then "Experimental. " ^ descr else descr in + Parameters.register_domain ~name ~descr + + let register_abstraction = function | Domain register -> RegisteredDomain (Leaf.register register) | Functor register -> RegisteredFunctor (Functor.register register) + let register ~name ~descr ?(experimental=false) ?(priority=0) register = + register_domain_option ~name ~descr ~experimental ; + let abstraction = register_abstraction register in + let registered = { name ; experimental ; priority ; abstraction } in + static_domains := registered :: !static_domains ; + abstraction + + let dynamic_register ~name ~descr ?(experimental=false) ?(priority=0) make = + register_domain_option ~name ~descr ~experimental ; + let make () = make () |> register_abstraction in + let make () = { name ; experimental ; priority ; abstraction = make () } in + dynamic_domains := (name, make) :: !dynamic_domains + (* Building the domain abstraction consists of structuring the requested registered domains. To do so, we need to keep track of the values and @@ -487,13 +524,16 @@ module Domain = struct (* Adding a registered domain into a structured one consists of performing a lifting of the registered one if needed before performing the product, configuring the name and restricting the domain depending of the mode. *) - let add (type v l) dname mode registered (structured : (v, l) structured) = + let add (type v l) (registered, mode) (structured : (v, l) structured) = + let wkey = Self.wkey_experimental in + let { experimental = exp ; name } = registered in + if exp then Self.warning ~wkey "The %s domain is experimental" name ; let module Structured = (val structured) in let module Loc = Structured.Location in let module Val = Structured.Value in let module Dom = Structured.Domain in let domain : (v, l) structured_domain = - match registered with + match registered.abstraction with | RegisteredFunctor (module Functor) -> let locs = Location.outline Functor.locations in let eq_loc = Location.dec_eq locs Loc.structure in @@ -538,7 +578,7 @@ module Domain = struct module Store = struct include Store let register_global_state storage state = - let no_results = Parameters.NoResultsDomains.mem dname in + let no_results = Parameters.NoResultsDomains.mem registered.name in register_global_state (storage && not no_results) state end end in @@ -564,640 +604,147 @@ module Domain = struct end : Structured with type value = v and type location = l) - - - - - - -end - - - - -(* --- Registration types --------------------------------------------------- *) - -type 'v value = - | Single of (module Abstract_value.Leaf with type t = 'v) - | Struct of 'v Abstract.Value.structure - -type 'l location = - | SingleLoc of (module Abstract_location.Leaf with type location = 'l) - | StructLoc of 'l Abstract.Location.structure - -type ('v, 'l) leaf_domain = - (module Abstract_domain.Leaf with type location = 'l and type value = 'v) - -module type Functor_value = sig - type l - module Make (V: Abstract.Value.External) : - (Abstract_domain.Leaf with type value = V.t and type location = l) + (* Build a complete abstraction based on a list of registered domains and a + value initial configuration. *) + let build domains : (module Structured) = + let values = + let add_value = Value.{ folder = add } in + let add_values values (registered, _) = + match registered.abstraction with + | RegisteredDomain (module Domain) -> + Value.fold add_value Domain.values values |> + Location.fold_values add_value Domain.locations + | RegisteredFunctor (module F) -> + Location.fold_values add_value F.locations values + in + List.fold_left add_values Value.init domains |> + Value.make_interactive + in + let module V = (val values) in + let locations = + let init : V.t Location.structured = (module Location.Init (V)) in + let add_loc = Location.{ folder = add } in + let add_locations locs (registered, _) = + match registered.abstraction with + | RegisteredDomain (module D) -> Location.fold add_loc D.locations locs + | RegisteredFunctor (module D) -> Location.fold add_loc D.locations locs + in + List.fold_left add_locations init domains |> + Location.make_interactive + in + let module L = (val locations) in + let domain : (V.t, L.location) structured_domain = + (module Unit_domain.Make (V) (L)) + in + let structured : (V.t, L.location) structured = (module struct + type value = V.t + type location = L.location + module Value = V + module Location = L + module Domain = (val domain) + end) in + let structured = List.fold_left (fun s d -> add d s) structured domains in + let module Structured : Structured = (val structured) in + (module Structured) end -type ('v, 'l) domain = - | Domain : ('v, 'l) leaf_domain -> ('v, 'l) domain - | FunctorValue : (module Functor_value with type l = 'l) -> (_, 'l) domain - -type ('v, 'l) abstraction = - { values: 'v value - ; location: 'l location - ; domain : ('v, 'l) domain - } - -type 't with_info = - { name: string - ; experimental: bool - ; priority: int - ; abstraction: 't - } - -type flag = Flag: ('v, 'l) abstraction with_info -> flag - - -type ('a, 'b) dec_eq = ('a, 'b) Structure.eq option - - - -(* --- Config and registration ---------------------------------------------- *) - -module Config = struct - module OptMode = Datatype.Option (Domain_mode) - module Element = struct - type t = flag * Domain_mode.t option - - (* Flags are sorted by increasing priority order, and then by name. *) - let compare (Flag f1, mode1) (Flag f2, mode2) = - let c = Datatype.Int.compare f1.priority f2.priority in - if c <> 0 then c else - let c = Datatype.String.compare f1.name f2.name in - if c <> 0 then c else - OptMode.compare mode1 mode2 - end - - include Set.Make (Element) - let mem (Flag domain) = - exists (fun (Flag flag, _mode) -> flag.name = domain.name) - let abstractions = ref [] - let dynamic_abstractions = ref [] +(* --- Configuration -------------------------------------------------------- *) - let register_domain_option ~name ~experimental ~descr = - let descr = if experimental then "Experimental. " ^ descr else descr in - Parameters.register_domain ~name ~descr +module Configuration = struct + module Mode = Datatype.Option (Domain_mode) - let register ~name ~descr ?(experimental=false) ?(priority=0) abstraction = - register_domain_option ~name ~experimental ~descr; - let flag = Flag { name; experimental; priority; abstraction } in - abstractions := flag :: !abstractions; - flag - - let dynamic_register ~name ~descr ?(experimental=false) ?(priority=0) make = - register_domain_option ~name ~experimental ~descr; - let make' () : flag = - Flag { name; experimental; priority; abstraction = make () } - in - dynamic_abstractions := (name,make') :: !dynamic_abstractions + include Set.Make (struct + open Domain + type t = registered with_info with_mode + let compare (d1, m1) (d2, m2) = + let c = Datatype.Int.compare d1.priority d2.priority in + if c = 0 then + let c = Datatype.String.compare d1.name d2.name in + if c = 0 then Mode.compare m1 m2 else c + else c + end) let configure () = - let add_main_mode mode = - let main, _ = Globals.entry_point () in - (main, Domain_mode.Mode.all) :: mode - in - let add config (name, make) = + let find = Parameters.DomainsFunction.find in + let find name = try Some (find name) with Not_found -> None in + let main = Globals.entry_point () |> fst in + let add_main_mode modes = (main, Domain_mode.Mode.all) :: modes in + let dynamic (name, make) config = let enabled = Parameters.Domains.mem name in - try - let mode = Parameters.DomainsFunction.find name in - let mode = if enabled then add_main_mode mode else mode in - add (make (), Some mode) config - with Not_found -> - if enabled then add (make (), None) config else config + let enable modes = if enabled then add_main_mode modes else modes in + match find name with + | None -> if enabled then add (make (), None) config else config + | Some modes -> add (make (), Some (enable modes)) config in - let aux config (Flag domain as flag) = - add config (domain.name, (fun () -> flag)) - in - let config = List.fold_left aux empty !abstractions in - List.fold_left add config !dynamic_abstractions - - (* --- Register default abstractions -------------------------------------- *) - - let create_domain ?experimental priority name descr values location domain = - let values = Single values in - let location = SingleLoc location in - let domain = Domain domain in - let abstraction = { values ; location ; domain } in - register ~name ~descr ~priority ?experimental abstraction - - (* Register standard domains over cvalues. *) - let make ?experimental rank name descr = - create_domain ?experimental rank name descr - (module Main_values.CVal) (module Main_locations.PLoc) - - let cvalue = - make 9 "cvalue" - "Main analysis domain, enabled by default. Should not be disabled." - (module Cvalue_domain.State) - - let symbolic_locations = - make 7 "symbolic-locations" - "Infers values of symbolic locations represented by imprecise lvalues, \ - such as t[i] or *p when the possible values of [i] or [p] are imprecise." - (module Symbolic_locs.D) - - (* TODO: Location handling in equality functor *) - let equality = - let descr = "Infers equalities between syntactic C expressions. \ - Makes the analysis less dependent on temporary variables and \ - intermediate computations." - and abstraction = - { values = Struct Abstract.Value.Unit; - location = SingleLoc (module Main_locations.PLoc); - domain = FunctorValue (module struct - type l = Main_locations.PLoc.location - module Make = Equality_domain.Make - end); } - in - register ~name:"equality" ~descr ~priority:8 abstraction - - let gauges = - make 6 "gauges" - "Infers linear inequalities between the variables modified within a loop \ - and a special loop counter." - (module Gauges_domain.D) - - let octagon = - make 6 "octagon" - "Infers relations between scalar variables of the form b ≤ ±X ± Y ≤ e, \ - where X, Y are program variables and b, e are constants." - (module Octagons) - - let bitwise = - create_domain 3 "bitwise" - "Infers bitwise information to interpret more precisely bitwise operators." - (module Offsm_value.Offsm) (module Main_locations.PLoc) (module Offsm_domain.D) - - let sign = - create_domain 4 "sign" - "Infers the sign of program variables." - (module Sign_value) (module Main_locations.PLoc) (module Sign_domain) - - let inout = make 5 "inout" ~experimental:true - "Infers the inputs and outputs of each function." - (module Inout_domain.D) - - let traces = - make 2 "traces" ~experimental:true - "Builds an over-approximation of all the traces that lead \ - to a statement." - (module Traces_domain.D) - - let printer = - make 2 "printer" - "Debug domain, only useful for developers. Prints the transfer functions \ - used during the analysis." - (module Printer_domain) - - (* --- Default and legacy configurations ---------------------------------- *) - - let default = configure () - let legacy = singleton (cvalue, None) + let static d = dynamic (d.Domain.name, fun () -> d) in + let fold f xs acc = List.fold_left (fun acc x -> f x acc) acc xs in + fold static !Domain.static_domains empty |> + fold dynamic !Domain.dynamic_domains end -let register = Config.register -let dynamic_register = Config.dynamic_register - - - -(* --- Building value abstractions ------------------------------------------ *) - -module Leaf_Value (V: Abstract_value.Leaf) = struct - include V - let structure = Abstract.Value.Leaf (V.key, (module V)) -end - -module Internal_Value = struct - open Abstract.Value - - let eq_value : type a b. a structure -> b value -> (a, b) dec_eq = - fun structure -> function - | Struct s -> eq_structure structure s - | Single (module V) -> - match structure with - | Leaf (key, _) -> eq_type key V.key - | _ -> None - type value_key_module = V : 'v key * 'v data -> value_key_module - let open_value_abstraction (module Value : Internal) = - (module struct - include Value - include Structure.Open (Abstract.Value) (Value) - end : Abstract.Value.External) - - let add_value_leaf value (V (key, v)) = - let module Value = (val open_value_abstraction value) in - if Value.mem key then value else - (module struct - include Value_product.Make (Value) (val v) - let structure = Node (Value.structure, Leaf (key, v)) - end) - - let void_value () = - Self.fatal "Cannot register a value module from a Void structure." - - let add_value_structure value internal = - let rec aux: type v. (module Internal) -> v structure -> (module Internal) = - fun value -> function - | Option (s, _) -> aux value s - | Leaf (key, v) -> add_value_leaf value (V (key, v)) - | Node (s1, s2) -> aux (aux value s1) s2 - | Unit -> value - | Void -> void_value () - in - aux value internal +(* --- Value reduced product ----------------------------------------------- *) - let build_values config initial_value = - let build (Flag flag, _) acc = - match flag.abstraction.values with - | Struct structure -> add_value_structure acc structure - | Single (module V) -> add_value_leaf acc (V (V.key, (module V))) - in - let value = Config.fold build config initial_value in - open_value_abstraction value - - module type Struct = sig type v val s : v value end - - module Convert (Value: Abstract.Value.External) (Struct: Struct) = struct - type extended = Value.t - - let structure = - match Struct.s with - | Single (module V) -> Abstract.Value.Leaf (V.key, (module V)) - | Struct s -> s - - let replace = - let rec set: type v. v structure -> v -> Value.t -> Value.t = function - | Leaf (key, _) -> Value.set key - | Node (s1, s2) -> - let set1 = set s1 and set2 = set s2 in - fun (v1, v2) value -> set1 v1 (set2 v2 value) - | Option (s, default) -> fun v -> set s (Option.value ~default v) - | Unit -> fun () value -> value - | Void -> void_value () - in - set structure - - let extend v = replace v Value.top - - let restrict = - let rec get: type v. v structure -> Value.t -> v = function - | Leaf (key, _) -> Option.get (Value.get key) - | Node (s1, s2) -> - let get1 = get s1 and get2 = get s2 in - fun v -> get1 v, get2 v - | Option (s, _) -> fun v -> Some (get s v) - | Unit -> fun _ -> () - | Void -> void_value () - in - get structure +module Reducer = struct + module type S = sig + include Abstract.Value.External + val reduce : t -> t end -end - + type 'a key = 'a Value.key + type ('a, 'b) reducer = 'a -> 'b -> 'a * 'b + type action = Action : 'a key * 'b key * ('a, 'b) reducer -> action -(* --- Building value abstractions ------------------------------------------ *) + let actions = ref [] -module Leaf_Location (Loc: Abstract_location.Leaf) = struct - include Loc - let structure = Abstract.Location.Leaf (Loc.key, (module Loc)) -end + let register left right reducer = + actions := (Action (left, right, reducer)) :: !actions -module Internal_Loc = struct - open Abstract.Location + module Make (Value : Abstract.Value.External) = struct + include Value - let eq_loc : type a b. a structure -> b location -> (a, b) dec_eq = - fun structure -> function - | StructLoc s -> eq_structure structure s - | SingleLoc (module L) -> - match structure with - | Leaf (key, _) -> eq_type key L.key - | _ -> None + let make_reduction acc (Action (key1, key2, f)) = + match Value.get key1, Value.get key2 with + | Some get1, Some get2 -> + let set1 = Value.set key1 and set2 = Value.set key2 in + let reduce v = f (get1 v) (get2 v) in + let reducer v = let v1, v2 = reduce v in set1 v1 (set2 v2 v) in + reducer :: acc + | _, _ -> acc - type loc_key_module = L : 'l key * 'l data -> loc_key_module - - let open_loc_abstraction (module Loc : Internal) = - (module struct - include Loc - include Structure.Open (Abstract.Location) (struct - include Loc - type t = location - end) - end : Abstract.Location.External) - - (* TODO: Location product ? *) - let add_loc_leaf loc (L (key, _l)) = - let module Loc = (val open_loc_abstraction loc) in - if Loc.mem key then loc else - (* (module struct *) - (* include Location_product.Make (Loc) (val l) *) - (* let structure = Node (Loc.structure, Leaf (key, l)) *) - (* end) *) - assert false - - let void_loc () = - Self.fatal "Cannot register a location module from a Void structure." - - let add_loc_structure loc internal = - let rec aux: type l. (module Internal) -> l structure -> (module Internal) = - fun loc -> function - | Option (s, _) -> aux loc s - | Leaf (key, v) -> add_loc_leaf loc (L (key, v)) - | Node (s1, s2) -> aux (aux loc s1) s2 - | Unit -> loc - | Void -> void_loc () - in - aux loc internal - - let build_locs config initial_loc = - let build (Flag flag, _) acc = - match flag.abstraction.location with - | StructLoc structure -> add_loc_structure acc structure - | SingleLoc (module L) -> add_loc_leaf acc (L (L.key, (module L))) - in - Config.fold build config initial_loc |> open_loc_abstraction - - module type Struct = sig type l val s : l location end - - module Convert (Loc: Abstract.Location.External) (Struct: Struct) = struct - type extended = Loc.location - - let structure = - match Struct.s with - | SingleLoc (module L) -> Abstract.Location.Leaf (L.key, (module L)) - | StructLoc s -> s - - let replace = - let rec set: type l. l structure -> l -> Loc.location -> Loc.location = function - | Leaf (key, _) -> Loc.set key - | Node (s1, s2) -> - let set1 = set s1 and set2 = set s2 in - fun (l1, l2) loc -> set1 l1 (set2 l2 loc) - | Option (s, default) -> fun l -> set s (Option.value ~default l) - | Unit -> fun () loc -> loc - | Void -> void_loc () - in - set structure - - let extend l = replace l Loc.top - - let restrict = - let rec get: type l. l structure -> Loc.location -> l = function - | Leaf (key, _) -> Option.get (Loc.get key) - | Node (s1, s2) -> - let get1 = get s1 and get2 = get s2 in - fun l -> get1 l, get2 l - | Option (s, _) -> fun l -> Some (get s l) - | Unit -> fun _ -> () - | Void -> void_loc () - in - get structure + let reduce = + let list = List.fold_left make_reduction [] !actions in + fun v -> List.fold_left (fun v reduce -> reduce v) v list end end -(* --- Building domain abstractions ----------------------------------------- *) - -module type Acc = sig - module Val : Abstract.Value.External - module Loc : Abstract.Location.External - with type value = Val.t - module Dom : Abstract.Domain.Internal - with type value = Val.t and type location = Loc.location -end - -module Leaf_Domain (D: Abstract_domain.Leaf) = struct - include D - let structure = Abstract.Domain.Leaf (D.key, (module D)) -end - - -module type Typ = sig type t end -let conversion_id (type t) (module T: Typ with type t = t) = - (module struct - type extended = T.t - type internal = T.t - let extend x = x - let restrict x = x - end: Domain_lift.Conversion with type extended = t and type internal = t) - -type ('v, 'l) internal_domain = - (module Abstract.Domain.Internal with type value = 'v and type location = 'l) - -let add_domain (type v) (type l) dname mode (abstraction: (v, l) abstraction) (module Acc: Acc) = - let domain : (Acc.Val.t, Acc.Loc.location) internal_domain = - let eq_loc = Internal_Loc.eq_loc Acc.Loc.structure abstraction.location in - match abstraction.domain with - | FunctorValue (module Functor) -> - let module Domain = Leaf_Domain (Functor.Make (Acc.Val)) in - begin match eq_loc with - | Some Structure.Eq -> (module Domain) - | None -> - let module ConvertVal = (val conversion_id (module Acc.Val)) in - let module ConvertLoc = Internal_Loc.Convert (Acc.Loc) (struct - type l = Domain.location - let s = abstraction.location - end) in - (module Domain_lift.Make (Domain) (ConvertVal) (ConvertLoc)) - end - | Domain (module Domain) -> - let eq_value = Internal_Value.eq_value Acc.Val.structure abstraction.values in - match eq_value, eq_loc with - | Some Structure.Eq, Some Structure.Eq -> (module Leaf_Domain (Domain)) - | Some Structure.Eq, None -> - let module ConvertVal = (val conversion_id (module Acc.Val)) in - let module ConvertLoc = Internal_Loc.Convert (Acc.Loc) (struct - type l = Domain.location - let s = abstraction.location - end) in - (module Domain_lift.Make (Domain) (ConvertVal) (ConvertLoc)) - | None, Some Structure.Eq -> - let module ConvertVal = Internal_Value.Convert (Acc.Val) (struct - type v = Domain.value - let s = abstraction.values - end) in - let module LocTyp = struct type t = Acc.Loc.location end in - let module ConvertLoc = (val conversion_id (module LocTyp)) in - (module Domain_lift.Make (Domain) (ConvertVal) (ConvertLoc)) - | None, None -> - let module ConvertVal = Internal_Value.Convert (Acc.Val) (struct - type v = Domain.value - let s = abstraction.values - end) in - let module ConvertLoc = Internal_Loc.Convert (Acc.Loc) (struct - type l = Domain.location - let s = abstraction.location - end) in - (module Domain_lift.Make (Domain) (ConvertVal) (ConvertLoc)) - in - (* Set the name of the domain. *) - let module Domain = struct - include (val domain) - module Store = struct - include Store - let register_global_state storage state = - let no_results = Parameters.NoResultsDomains.mem dname in - register_global_state (storage && not no_results) state - end - end in - (* Restricts the domain according to [mode]. *) - let domain : (Acc.Val.t, Acc.Loc.location) internal_domain = - match mode with - | None -> (module Domain) - | Some kf_modes -> - let module Scope = struct let functions = kf_modes end in - let module Domain = - Domain_builder.Restrict - (Acc.Val) - (Domain) - (Scope) - in - (module Domain) - in - let domain : (Acc.Val.t, Acc.Loc.location) internal_domain = - match Abstract.Domain.(eq_structure Acc.Dom.structure Unit) with - | Some _ -> domain - | None -> - (* The new [domain] becomes the left leaf of the domain product, and will - be processed before the domains from [Acc.Dom] during the analysis. *) - (module Domain_product.Make (Acc.Val) ((val domain)) (Acc.Dom)) - in - (module struct - module Val = Acc.Val - module Loc = Acc.Loc - module Dom = (val domain) - end : Acc) - -let warn_experimental flag = - if flag.experimental then - Self.(warning ~wkey:wkey_experimental - "The %s domain is experimental." flag.name) - -let build_domain config abstract = - let build (Flag flag, mode) acc = - warn_experimental flag; - add_domain flag.name mode flag.abstraction acc - in - (* Domains in the [config] are sorted by increasing priority: domains with - higher priority are added last: they will be at the top of the domains - tree, and thus will be processed first during the analysis. *) - Config.fold build config abstract - - - -(* --- Value reduced product ----------------------------------------------- *) - -module type Value = sig - include Abstract.Value.External - val reduce : t -> t -end +(* --- Finalizing abstractions build ---------------------------------------- *) module type S = sig - module Val : Value - module Loc : Abstract.Location.External - with type value = Val.t + module Val : Reducer.S + module Loc : Abstract.Location.External with type value = Val.t 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 - - -type ('a, 'b) value_reduced_product = - 'a Abstract.Value.key * 'b Abstract.Value.key * ('a -> 'b -> 'a * 'b) - -type v_reduced_product = R: ('a, 'b) value_reduced_product -> v_reduced_product - -let value_reduced_product = ref [] - -let register_value_reduction reduced_product = - value_reduced_product := (R reduced_product) :: !value_reduced_product - -(* When the value abstraction contains both a cvalue and an interval - component (coming currently from an Apron domain), reduce them from each - other. If the Cvalue is not a scalar do nothing, because we do not - currently use Apron for pointer offsets. *) -let reduce_apron_itv cvalue ival = - match ival with - | None -> begin - try cvalue, Some (Cvalue.V.project_ival cvalue) - with Cvalue.V.Not_based_on_null -> cvalue, ival - end - | Some ival -> - try - let ival' = Cvalue.V.project_ival cvalue in - if Ival.is_int ival' - then - let reduced_ival = Ival.narrow ival ival' in - let cvalue = Cvalue.V.inject_ival reduced_ival in - cvalue, Some reduced_ival - else cvalue, Some ival - with Cvalue.V.Not_based_on_null -> cvalue, Some ival - -let () = - register_value_reduction - (Main_values.CVal.key, Main_values.Interval.key, reduce_apron_itv) - -module Reduce (Value : Abstract.Value.External) = struct - include Value - - let make_reduction acc (R (key1, key2, f)) = - match Value.get key1, Value.get key2 with - | Some get1, Some get2 -> - let set1 = Value.set key1 - and set2 = Value.set key2 in - let reduce v = let v1, v2 = f (get1 v) (get2 v) in set1 v1 (set2 v2 v) in - reduce :: acc - | _, _ -> acc - - let reduce = - let list = List.fold_left make_reduction [] !value_reduced_product in - fun v -> List.fold_left (fun v reduce -> reduce v) v list +module Hooks = struct + let hooks = ref [] + type hook = (module S) -> (module S) + let register (f : hook) = hooks := f :: !hooks + let apply abst = List.fold_left (fun acc f -> f acc) abst !hooks end - - -(* --- Final hook ----------------------------------------------------------- *) - -let final_hooks = ref [] - -let register_hook f = - final_hooks := f :: !final_hooks - -let apply_final_hooks abstractions = - List.fold_left (fun acc f -> f acc) abstractions !final_hooks - - - -(* --- Building abstractions ------------------------------------------------ *) - -module Open (Acc: Acc) : S = struct - module Val = Reduce (Acc.Val) - module Loc = struct - include Acc.Loc - include Structure.Open (Abstract.Location) - (struct include Acc.Loc type t = location end) - end +module Open (Structured : Domain.Structured) : S = struct + module Val = Reducer.Make (Structured.Value) + module Loc = Structured.Location module Dom = struct - include Acc.Dom - include Structure.Open (Abstract.Domain) (Acc.Dom) + include Structured.Domain + include Structure.Open (Abstract.Domain) (Structured.Domain) let get_cvalue = match get Cvalue_domain.State.key with | None -> None @@ -1213,53 +760,18 @@ module Open (Acc: Acc) : S = struct end end -module CVal = Leaf_Value (Main_values.CVal) - -let unit_acc (type v) - (module Value: Abstract.Value.External with type t = v) - (module Loc: Abstract.Location.External with type value = v) = - (module struct - module Val = Value - module Loc = Loc - module Dom = Unit_domain.Make (Val) (Loc) - end: Acc) - -(* let unit_acc (module Value: Abstract.Value.External) = *) -(* let loc : (module Abstract.Location.Internal with type value = Value.t) = *) -(* match Abstract.Value.eq_structure Value.structure CVal.structure with *) -(* | Some Structure.Eq -> (module Leaf_Location (Main_locations.PLoc)) *) -(* | _ -> *) -(* let module Struct = struct *) -(* type v = Cvalue.V.t *) -(* let s = Single (module Main_values.CVal) *) -(* end in *) -(* let module Conv = Internal_Value.Convert (Value) (Struct) in *) -(* (module Location_lift.Make (Main_locations.PLoc) (Conv)) *) -(* in *) -(* (module struct *) -(* module Val = Value *) -(* module Loc = (val loc) *) -(* module Dom = Unit_domain.Make (Val) (Loc) *) -(* end : Acc) *) - -let build_abstractions config = - let initial_loc = (module Main_locations.PLoc: Abstract.Location.Internal) in - let initial_value : (module Abstract.Value.Internal) = - if Config.mem Config.bitwise config - then (module Offsm_value.CvalueOffsm) - else (module CVal) - in - let value = Internal_Value.build_values config initial_value in - let loc = Internal_Loc.build_locs config initial_loc in - let acc = unit_acc value loc in - build_domain config acc - -let configure = Config.configure +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 let make config = - let abstractions = build_abstractions config in - let abstractions = (module Open (val abstractions): S) in - apply_final_hooks abstractions + let abstractions = Configuration.elements config |> Domain.build in + let abstractions = (module Open (val abstractions) : S) in + Hooks.apply abstractions -module Default = (val make Config.default) -module Legacy = (val make Config.legacy) +module Default = (val make (Configuration.configure ())) diff --git a/src/plugins/eva/engine/abstractions.mli b/src/plugins/eva/engine/abstractions.mli index be3c32e0515..755e771a050 100644 --- a/src/plugins/eva/engine/abstractions.mli +++ b/src/plugins/eva/engine/abstractions.mli @@ -20,6 +20,134 @@ (* *) (**************************************************************************) + + +module Value : sig + type 'v key = 'v Abstract.Value.key + type 'v value = (module Abstract_value.S with type t = 'v) + + type 'v registered + type 'v register = { key : 'v key ; value : 'v value } + val register : 'v register -> 'v registered + + type 'v dependencies = + | Last : 'v registered -> 'v dependencies + | (::) : 'a registered * 'b dependencies -> ('a * 'b) dependencies +end + + + +module Location : sig + type 'l key = 'l Abstract.Location.key + type ('v, 'l) location = + (module Abstract_location.S with type value = 'v and type location = 'l) + + type 'l registered + type ('v, 'l) register = + { key : 'l key + ; location : ('v, 'l) location + ; dependencies : 'v Value.dependencies + } + + val register : ('v, 'l) register -> 'l registered + + type 'l dependencies = + | Last : 'l registered -> 'l dependencies + | (::) : 'a registered * 'b dependencies -> ('a * 'b) dependencies +end + + + +module Domain : sig + type 's key = 's Abstract.Domain.key + + module Leaf : sig + type ('v, 'l, 's) domain = + (module Abstract_domain.S + with type value = 'v and type location = 'l and type state = 's) + + type ('v, 'l, 's) register = + { key : 's key + ; domain : ('v, 'l, 's) domain + ; values : 'v Value.dependencies + ; locations : 'l Location.dependencies + } + end + + module Functor : sig + module type Domain = sig + type location + module Make (V : Abstract.Value.External) : sig + include Abstract_domain.S + with type value = V.t and type location = location + val key : state key + end + end + + type 'l domain = (module Domain with type location = 'l) + + type 'l register = + { domain : 'l domain + ; locations : 'l Location.dependencies + } + end + + type registered + type register = + | Domain : ('v, 'l, 's) Leaf.register -> register + | Functor : 'l Functor.register -> register + + val register : + name:string -> descr:string -> ?experimental:bool -> ?priority:int -> + register -> registered + + val dynamic_register : + name:string -> descr:string -> ?experimental:bool -> ?priority:int -> + (unit -> register) -> unit +end + + + +module Reducer : sig + module type S = sig + include Abstract.Value.External + val reduce : t -> t + end + + type 'a key = 'a Value.key + type ('a, 'b) reducer = 'a -> 'b -> 'a * 'b + + val register : 'a key -> 'b key -> ('a, 'b) reducer -> unit +end + + + +module type S = sig + module Val : Reducer.S + module Loc : Abstract.Location.External with type value = Val.t + module Dom : Abstract.Domain.External + with type value = Val.t and type location = Loc.location +end + +module Hooks : sig + type hook = (module S) -> (module S) + val register : hook -> unit +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 + +module Default : S + + +(* + (** Registration and building of the analysis abstractions. *) (** {2 Registration of abstractions.} *) @@ -179,3 +307,5 @@ val make: Config.t -> (module S) module Legacy : S module Default : S + +*) -- GitLab