diff --git a/Makefile b/Makefile index ce5d740b6d4f2ffd7428765694e2e42949dd6b68..a4ba43c60ea3355165bafcb0f4fbabaec98098e3 100644 --- a/Makefile +++ b/Makefile @@ -821,52 +821,29 @@ PLUGIN_TESTS_DIRS+=value/traces # Files for the binding to Apron domains. Only available if Apron is available. ifeq ($(HAS_APRON),yes) PLUGIN_REQUIRES+= apron.octMPQ apron.boxMPQ apron.polkaMPQ apron.apron gmp -src/plugins/value/domains/apron/apron_domain.ml: \ - src/plugins/value/domains/apron/apron_domain.ok.ml \ - share/Makefile.config - $(CP_IF_DIFF) $< $@ - $(CHMOD_RO) $@ +APRON_CMO:= domains/apron/apron_domain else -src/plugins/value/domains/apron/apron_domain.ml: \ - src/plugins/value/domains/apron/apron_domain.ko.ml \ - share/Makefile.config - $(CP_IF_DIFF) $< $@ - $(CHMOD_RO) $@ -endif -PLUGIN_GENERATED+= src/plugins/value/domains/apron/apron_domain.ml +APRON_CMO:= PLUGIN_DISTRIB_EXTERNAL+= \ - domains/apron/apron_domain.ok.ml domains/apron/apron_domain.ko.ml + domains/apron/apron_domain.ml domains/apron/apron_domain.mli +endif # Files for the numerors domain. Only available is MPFR is available. NUMERORS_FILES:= \ values/numerors/numerors_utils values/numerors/numerors_float \ values/numerors/numerors_interval values/numerors/numerors_arithmetics \ - values/numerors/numerors_value + values/numerors/numerors_value domains/numerors/numerors_domain ifeq ($(HAS_MPFR),yes) PLUGIN_REQUIRES+= gmp PLUGIN_TESTS_DIRS+=value/numerors NUMERORS_CMO:= $(NUMERORS_FILES) -src/plugins/value/domains/numerors/numerors_domain.ml: \ - src/plugins/value/domains/numerors/numerors_domain.ok.ml \ - share/Makefile.config - $(CP_IF_DIFF) $< $@ - $(CHMOD_RO) $@ else # Do not compile numerors files, but include them in the distributed files. NUMERORS_CMO:= PLUGIN_DISTRIB_EXTERNAL+= $(addsuffix .ml,$(NUMERORS_FILES)) PLUGIN_DISTRIB_EXTERNAL+= $(addsuffix .mli,$(NUMERORS_FILES)) -src/plugins/value/domains/numerors/numerors_domain.ml: \ - src/plugins/value/domains/numerors/numerors_domain.ko.ml \ - share/Makefile.config - $(CP_IF_DIFF) $< $@ - $(CHMOD_RO) $@ endif -PLUGIN_GENERATED+= src/plugins/value/domains/numerors/numerors_domain.ml -PLUGIN_DISTRIB_EXTERNAL+= \ - domains/numerors/numerors_domain.ok.ml \ - domains/numerors/numerors_domain.ko.ml # General rules for ordering files within PLUGIN_CMO: # - try to keep the legacy Value before Eva @@ -878,7 +855,7 @@ PLUGIN_CMO:= slevel/split_strategy value_parameters \ slevel/per_stmt_slevel \ utils/library_functions \ utils/eval_typ utils/backward_formals \ - alarmset eval utils/structure \ + alarmset eval utils/structure utils/abstract \ values/value_product values/location_lift \ values/cvalue_forward values/cvalue_backward \ values/main_values values/main_locations \ @@ -890,13 +867,11 @@ PLUGIN_CMO:= slevel/split_strategy value_parameters \ domains/traces_domain \ domains/simple_memory \ domains/gauges/gauges_domain \ - domains/apron/apron_domain \ domains/hcexprs \ domains/equality/equality domains/equality/equality_domain \ domains/offsm_domain \ domains/symbolic_locs \ domains/sign_domain \ - $(NUMERORS_CMO) domains/numerors/numerors_domain \ domains/cvalue/warn domains/cvalue/locals_scoping \ domains/cvalue/cvalue_offsetmap \ utils/value_results \ @@ -918,7 +893,8 @@ PLUGIN_CMO:= slevel/split_strategy value_parameters \ engine/partition engine/partitioning_parameters engine/trace_partitioning \ engine/iterator \ engine/initialization \ - engine/compute_functions engine/analysis register + engine/compute_functions engine/analysis register \ + $(APRON_CMO) $(NUMERORS_CMO) PLUGIN_CMI:= values/abstract_value values/abstract_location \ domains/abstract_domain domains/simpler_domains PLUGIN_DEPENDENCIES:=Callgraph LoopAnalysis RteGen diff --git a/headers/header_spec.txt b/headers/header_spec.txt index f5f65ba9305df53bb4a95afcc297f6bfe441ab7a..b66be1d6251f0bfde9c04b103943158952b9c1c6 100644 --- a/headers/header_spec.txt +++ b/headers/header_spec.txt @@ -1272,6 +1272,8 @@ src/plugins/value/slevel/split_strategy.ml: CEA_LGPL_OR_PROPRIETARY src/plugins/value/slevel/split_strategy.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/value/test.assert.sh: .ignore src/plugins/value/test.sh: .ignore +src/plugins/value/utils/abstract.ml: CEA_LGPL_OR_PROPRIETARY +src/plugins/value/utils/abstract.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/value/utils/backward_formals.ml: CEA_LGPL_OR_PROPRIETARY src/plugins/value/utils/backward_formals.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/value/utils/eval_typ.ml: CEA_LGPL_OR_PROPRIETARY diff --git a/src/plugins/value/domains/abstract_domain.mli b/src/plugins/value/domains/abstract_domain.mli index 9ddb17082d70603ad752fecbcb7898de4d857cf4..4c77a1475887504958c8884cd540d0bdf5697822 100644 --- a/src/plugins/value/domains/abstract_domain.mli +++ b/src/plugins/value/domains/abstract_domain.mli @@ -396,73 +396,12 @@ module type S = sig val initialize_variable_using_type: init_kind -> varinfo -> t -> t include Recycle with type t := t -end - - -(** Keys identify abstract domains through the type of their abstract values. *) -type 'a key = 'a Structure.Key_Domain.k - -(** Describes the internal structure of a domain. - Used internally to automatically generate efficient accessors from a - generic abstract domain, which may be a combination of several domains, - to a specific one. *) -type 'a structure = 'a Structure.Key_Domain.structure = - | Void : 'a structure - | Leaf : 'a key -> 'a structure - | Node : 'a structure * 'b structure -> ('a * 'b) structure - -(** - For a simple 'leaf' domain, the structure should be: - [let key = Structure.Key_Domain.create_key "name_of_the_domain";; - let structure = Leaf key;;] - - Then, the key should be exported by the domain, to allow the use of the - functions defined in the {!Interface} interface below. - - A compound domain may use the {!Node} constructor to provide a separate - access to each of its parts. - - A domain can also use the {!Void} constructor to prevent access to itself. -*) - -(** Structure of a domain. *) -module type S_with_Structure = sig - include S - - (** A structure matching the type of the domain. *) - val structure : t structure (** Category for the messages about the domain. Must be created through {!Value_parameters.register_category}. *) val log_category : Value_parameters.category end -(** External interface of a domain, with accessors. - Automatically built by the functor {!Structure.Open}. - When a generic domain is a combination of several domains, these functions - allow interacting with its subparts. Note that their behavior is undefined - if the overall domain contains several times the same domain. *) -module type Interface = sig - type t - - (** Tests whether a key belongs to the domain. *) - val mem : 'a key -> bool - - (** For a key of type [k key]: - - if the states of this domain (of type [t]) contain a part (of type [k]) - from the domain identified by the key, - then [get key] returns an accessor for this part of a state. - - otherwise, [get key] returns None. *) - val get : 'a key -> (t -> 'a) option - - (** For a key of type [k key]: - - if the states of this domain (of type [t]) contain a part (of type [k]) - from the domain identified by the key, - then [set key d state] returns the state [state] in which this part - has been replaced by [d]. - - otherwise, [set key _] is the identity function. *) - val set : 'a key -> 'a -> t -> t -end (** Automatic storage of the states computed during the analysis. *) module type Store = sig @@ -487,7 +426,7 @@ end (** Full implementation of domains. Automatically built by {!Domain_builder.Complete} from an {!S_with_Structure} domain. *) module type Internal = sig - include S_with_Structure + include S module Store: Store with type state := state (** This function is called after the analysis. The argument is the state @@ -497,11 +436,14 @@ module type Internal = sig val post_analysis: t or_bottom -> unit end -(** Final interface of domains, as generated and used by Eva, with generic - accessors for domains. *) -module type External = sig +type 't key = 't Structure.Key_Domain.key + +(** Signature for a leaf module of a domain. *) +module type Leaf = sig include Internal - include Interface with type t := state + + (** The key identifies the domain and the type [t] of its states. *) + val key: t key end diff --git a/src/plugins/value/domains/apron/apron_domain.ko.ml b/src/plugins/value/domains/apron/apron_domain.ko.ml deleted file mode 100644 index 9ccb3680e2919874b7ad15a85c8b3c597e39083d..0000000000000000000000000000000000000000 --- a/src/plugins/value/domains/apron/apron_domain.ko.ml +++ /dev/null @@ -1,49 +0,0 @@ -(**************************************************************************) -(* *) -(* This file is part of Frama-C. *) -(* *) -(* Copyright (C) 2007-2019 *) -(* CEA (Commissariat à l'énergie atomique et aux énergies *) -(* alternatives) *) -(* *) -(* you can redistribute it and/or modify it under the terms of the GNU *) -(* Lesser General Public License as published by the Free Software *) -(* Foundation, version 2.1. *) -(* *) -(* It is distributed in the hope that it will be useful, *) -(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) -(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) -(* GNU Lesser General Public License for more details. *) -(* *) -(* See the GNU Lesser General Public License version 2.1 *) -(* for more details (enclosed in the file licenses/LGPLv2.1). *) -(* *) -(**************************************************************************) - -let ok = false - -module type S = Abstract_domain.Internal - with type value = Main_values.Interval.t - and type location = Precise_locs.precise_location - -module U = Unit_domain.Make (Main_values.Interval) (Main_locations.PLoc) - -module Octagon = U -module Box = U -module Polka_Loose = U -module Polka_Strict = U -module Polka_Equalities = U - -let dummy_key = Structure.Key_Domain.create_key "dummy_apron" -let octagon_key = dummy_key -let box_key = dummy_key -let polka_loose_key = dummy_key -let polka_strict_key = dummy_key -let polka_equalities_key = dummy_key - - -(* -Local Variables: -compile-command: "make -C ../../../.." -End: -*) diff --git a/src/plugins/value/domains/apron/apron_domain.ok.ml b/src/plugins/value/domains/apron/apron_domain.ml similarity index 95% rename from src/plugins/value/domains/apron/apron_domain.ok.ml rename to src/plugins/value/domains/apron/apron_domain.ml index e69f47ab8625886339479d8da73957603665d6aa..15035124c408a28ef47136b8b728305bdab97c97 100644 --- a/src/plugins/value/domains/apron/apron_domain.ok.ml +++ b/src/plugins/value/domains/apron/apron_domain.ml @@ -20,22 +20,14 @@ (* *) (**************************************************************************) -#24 "src/plugins/value/domains/apron/apron_domain.ok.ml" - open Cil_types open Eval open Apron let dkey = Value_parameters.register_category "d-apron" -let ok = true - let debug = false -module type S = Abstract_domain.Internal - with type value = Main_values.Interval.t - and type location = Precise_locs.precise_location - let abort exclog = let open Manager in Value_parameters.fatal @@ -357,22 +349,19 @@ let ival_to_interval = function (* Abstract Domain Functor *) (* -------------------------------------------------------------------------- *) -module Make - (Man: sig - type t - val manager: t Manager.t - val name: string - val key: t Abstract1.t Abstract_domain.key - end) -= struct +module type Input = sig + type t + val manager: t Manager.t + val name: string +end + +module Make (Man : Input) = struct type state = Man.t Abstract1.t type value = Main_values.Interval.t type location = Precise_locs.precise_location let man = Man.manager - - let structure = Abstract_domain.Leaf Man.key let log_category = dkey let empty_env = Environment.make [||] [||] @@ -725,54 +714,52 @@ module Make end -let octagon_key = Structure.Key_Domain.create_key "apron-octagon" -let box_key = Structure.Key_Domain.create_key "apron-box" -let polka_loose_key = Structure.Key_Domain.create_key "polka-loose" -let polka_strict_key = Structure.Key_Domain.create_key "polka-strict" -let polka_equalities_key = Structure.Key_Domain.create_key "polka-equalities" - - module Apron_Octagon = struct type t = Oct.t let manager = Oct.manager_alloc () let name = "Apron octagon domain" - let key = octagon_key end module Apron_Box = struct type t = Box.t let manager = Box.manager_alloc () let name = "Apron box domain" - let key = box_key end module Apron_Polka_Loose = struct type t = Polka.loose Polka.t let manager = Polka.manager_alloc_loose () let name = "Polka loose polyhedra domain" - let key = polka_loose_key end module Apron_Polka_Strict = struct type t = Polka.strict Polka.t let manager = Polka.manager_alloc_strict () let name = "Polka strict polyhedra domain" - let key = polka_strict_key end module Apron_Polka_Equalities = struct type t = Polka.equalities Polka.t let manager = Polka.manager_alloc_equalities () let name = "Polka linear equalities domain" - let key = polka_equalities_key end (** Apron manager allocation changes the rounding mode. *) let () = Floating_point.set_round_nearest_even () -module Octagon = Domain_builder.Complete (Make (Apron_Octagon)) -module Box = Domain_builder.Complete (Make (Apron_Box)) -module Polka_Loose = Domain_builder.Complete (Make (Apron_Polka_Loose)) -module Polka_Strict = Domain_builder.Complete (Make (Apron_Polka_Strict)) -module Polka_Equalities = Domain_builder.Complete (Make (Apron_Polka_Equalities)) +let make name enable (module Man: Input) = + let module Domain = Domain_builder.Complete (Make (Man)) in + let open Abstractions in + register ~enable { name; priority = 1; + values = Single (module Main_values.Interval); + domain = Domain (module Domain); } + +let () = + let open Value_parameters in + make "apron octagons" ApronOctagon.get (module Apron_Octagon); + make "apron box" ApronBox.get (module Apron_Box); + make "polka loose" PolkaLoose.get (module Apron_Polka_Loose); + make "polka strict" PolkaStrict.get (module Apron_Polka_Strict); + make "polka equalities" PolkaEqualities.get (module Apron_Polka_Equalities); + register_apron () (* diff --git a/src/plugins/value/domains/apron/apron_domain.mli b/src/plugins/value/domains/apron/apron_domain.mli index 19c6611afb1159e90e569e04971eec187da1bbab..5d86a35d509779c5d55ddf1de342b5f592f297fa 100644 --- a/src/plugins/value/domains/apron/apron_domain.mli +++ b/src/plugins/value/domains/apron/apron_domain.mli @@ -24,43 +24,6 @@ the APRON library: http://apron.cri.ensmp.fr/library For now, this binding only processes scalar integer variables. *) -(** Are apron domains available? *) -val ok : bool - -(** Signature of an Apron domain in Eva. *) -module type S = Abstract_domain.Internal - with type value = Main_values.Interval.t - and type location = Precise_locs.precise_location - - -(** Apron domains available for Eva. *) - -(** Octagons abstract domain. *) -module Octagon : S - -(** Intervals abstract domain. *) -module Box : S - -(** Loose polyhedra of the NewPolka library. - Cannot have strict inequality constraints. Algorithmically more efficient. *) -module Polka_Loose : S - -(** Strict polyhedra of the NewPolka library. *) -module Polka_Strict : S - -(** Linear equalities. *) -module Polka_Equalities : S - - -(** Domain keys for the Apron domains in Eva. *) - -val octagon_key : Octagon.t Abstract_domain.key -val box_key : Box.t Abstract_domain.key -val polka_loose_key : Polka_Loose.t Abstract_domain.key -val polka_strict_key : Polka_Strict.t Abstract_domain.key -val polka_equalities_key : Polka_Equalities.t Abstract_domain.key - - (* Local Variables: compile-command: "make -C ../../../.." diff --git a/src/plugins/value/domains/cvalue/cvalue_domain.ml b/src/plugins/value/domains/cvalue/cvalue_domain.ml index 841850c4fefb3bc6b3bc6b678eefa8887bf517fa..019f87cc0ee61fa5f2fb0ab04a5b43ce16e56256 100644 --- a/src/plugins/value/domains/cvalue/cvalue_domain.ml +++ b/src/plugins/value/domains/cvalue/cvalue_domain.ml @@ -22,15 +22,8 @@ open Eval -let key = Structure.Key_Domain.create_key "cvalue_domain" let dkey_card = Value_parameters.register_category "cardinal" -let extract get = match get key with - | None -> fun _ -> Cvalue.Model.top - | Some get -> function - | `Bottom -> Cvalue.Model.bottom - | `Value state -> get state - module Model = struct include Cvalue.Model @@ -168,10 +161,6 @@ module State = struct type state = Model.t * Locals_scoping.clobbered_set - let structure = - Abstract_domain.Node (Abstract_domain.Leaf key, - Abstract_domain.Leaf Locals_scoping.key) - let log_category = Value_parameters.dkey_cvalue_domain include Datatype.Make_with_collections ( @@ -193,6 +182,7 @@ module State = struct end ) let name = "Cvalue domain" + let key = Structure.Key_Domain.create_key "cvalue_domain" type value = Model.value type location = Model.location @@ -552,9 +542,6 @@ end let () = Db.Value.display := (fun fmt kf -> State.display ~fmt kf) -let inject cvalue_model = cvalue_model, Locals_scoping.bottom () -let project (state, _) = state - type prefix = Hptmap.prefix module Subpart = struct @@ -562,12 +549,12 @@ module Subpart = struct let hash = Model.hash_subtree let equal = Model.equal_subtree end -let distinct_subpart a b = +let distinct_subpart (a, _) (b, _) = if Model.equal a b then None else try Model.comp_prefixes a b; None with Model.Found_prefix (p, s1, s2) -> Some (p, s1, s2) -let find_subpart s prefix = Model.find_prefix s prefix +let find_subpart (s, _) prefix = Model.find_prefix s prefix (* Local Variables: diff --git a/src/plugins/value/domains/cvalue/cvalue_domain.mli b/src/plugins/value/domains/cvalue/cvalue_domain.mli index 34436ded0ad5db8a2d0b97d157f0d802891256a4..cf750b4e60f4caad41803517a7d468d98c6b948b 100644 --- a/src/plugins/value/domains/cvalue/cvalue_domain.mli +++ b/src/plugins/value/domains/cvalue/cvalue_domain.mli @@ -22,28 +22,18 @@ (** Main domain of the Value Analysis. *) -module State : Abstract_domain.Internal +module State : Abstract_domain.Leaf with type value = Main_values.CVal.t and type location = Main_locations.PLoc.location - - -val key : Cvalue.Model.t Abstract_domain.key - -val extract : - (Cvalue.Model.t Abstract_domain.key -> ('state -> Cvalue.Model.t) option) -> - 'state Eval.or_bottom -> Cvalue.Model.t - -val inject : Cvalue.Model.t -> State.t -val project : State.t -> Cvalue.Model.t - + and type state = Cvalue.Model.t * Locals_scoping.clobbered_set (** Specific functions for partitioning optimizations. *) type prefix module Subpart : Hashtbl.HashedType val distinct_subpart : - Cvalue.Model.t -> Cvalue.Model.t -> (prefix * Subpart.t * Subpart.t) option -val find_subpart : Cvalue.Model.t -> prefix -> Subpart.t option + State.t -> State.t -> (prefix * Subpart.t * Subpart.t) option +val find_subpart : State.t -> prefix -> Subpart.t option diff --git a/src/plugins/value/domains/cvalue/locals_scoping.ml b/src/plugins/value/domains/cvalue/locals_scoping.ml index 2059c345c71b2421ed931990f7471fccdfa83ad5..0399ececdacea419c547292619239e0b51aceea7 100644 --- a/src/plugins/value/domains/cvalue/locals_scoping.ml +++ b/src/plugins/value/domains/cvalue/locals_scoping.ml @@ -27,8 +27,6 @@ type clobbered_set = { mutable clob: Base.SetLattice.t } -let key = Structure.Key_Domain.create_key "clobbered_set" - let structural_descr = let open Structural_descr in t_record [| Base.SetLattice.packed_descr |] diff --git a/src/plugins/value/domains/cvalue/locals_scoping.mli b/src/plugins/value/domains/cvalue/locals_scoping.mli index e0b8c5d181d57181580186b48c8a832594d15550..8f0835453855fa211165d61038556ce98f03a81d 100644 --- a/src/plugins/value/domains/cvalue/locals_scoping.mli +++ b/src/plugins/value/domains/cvalue/locals_scoping.mli @@ -30,8 +30,6 @@ type clobbered_set = { mutable clob: Base.SetLattice.t } -val key: clobbered_set Abstract_domain.key - val structural_descr: Structural_descr.t val bottom: unit -> clobbered_set diff --git a/src/plugins/value/domains/domain_builder.ml b/src/plugins/value/domains/domain_builder.ml index b27b01329e10386ad60dee893ca52c897b1d10a5..7406f3753ddcdd15481c6defa1d9e2a36c403c12 100644 --- a/src/plugins/value/domains/domain_builder.ml +++ b/src/plugins/value/domains/domain_builder.ml @@ -22,7 +22,7 @@ module type InputDomain = sig - include Abstract_domain.S_with_Structure + include Abstract_domain.S val storage: unit -> bool end @@ -33,6 +33,9 @@ module Complete include Domain module Store = Domain_store.Make (Domain) + let key: Domain.t Structure.Key_Domain.key = + Structure.Key_Domain.create_key Domain.name + let post_analysis _state = () end @@ -57,7 +60,6 @@ module Make_Minimal include Domain - let structure = Abstract_domain.Void let log_category = Value_parameters.register_category ("d-" ^ name) type value = Value.t @@ -185,7 +187,6 @@ module Complete_Simple_Cvalue (Domain: Simpler_domains.Simple_Cvalue) (Domain) (struct let module_name = Domain.name end) : Datatype.S_with_collections with type t := t) - let structure = Abstract_domain.Void let log_category = Value_parameters.register_category ("d-" ^ name) type value = Cvalue.V.t diff --git a/src/plugins/value/domains/domain_builder.mli b/src/plugins/value/domains/domain_builder.mli index 7d3b426a606878abe05699292d827739fcec4948..1eddbb4b8b52625248ac77e374a6af904047cdf5 100644 --- a/src/plugins/value/domains/domain_builder.mli +++ b/src/plugins/value/domains/domain_builder.mli @@ -24,34 +24,34 @@ simplified interfaces. *) module type InputDomain = sig - include Abstract_domain.S_with_Structure + include Abstract_domain.S val storage: unit -> bool end module Complete (Domain: InputDomain) - : Abstract_domain.Internal with type state = Domain.state - and type value = Domain.value - and type location = Domain.location + : Abstract_domain.Leaf with type state = Domain.state + and type value = Domain.value + and type location = Domain.location module Complete_Minimal (Value: Abstract_value.S) (Location: Abstract_location.S) (Domain: Simpler_domains.Minimal) - : Abstract_domain.Internal with type value = Value.t - and type location = Location.location - and type state = Domain.t + : Abstract_domain.Leaf with type value = Value.t + and type location = Location.location + and type state = Domain.t module Complete_Minimal_with_datatype (Value: Abstract_value.S) (Location: Abstract_location.S) (Domain: Simpler_domains.Minimal_with_datatype) - : Abstract_domain.Internal with type value = Value.t - and type location = Location.location - and type state = Domain.t + : Abstract_domain.Leaf with type value = Value.t + and type location = Location.location + and type state = Domain.t module Complete_Simple_Cvalue (Domain: Simpler_domains.Simple_Cvalue) - : Abstract_domain.Internal with type value = Cvalue.V.t - and type location = Precise_locs.precise_location - and type state = Domain.t + : Abstract_domain.Leaf with type value = Cvalue.V.t + and type location = Precise_locs.precise_location + and type state = Domain.t diff --git a/src/plugins/value/domains/domain_lift.ml b/src/plugins/value/domains/domain_lift.ml index 02eaa96e98d63b5f8cccfe3bfa8463d6565ef361..0256e97c80d334675f3171ec8e0e2dfb1eb4ae86 100644 --- a/src/plugins/value/domains/domain_lift.ml +++ b/src/plugins/value/domains/domain_lift.ml @@ -37,7 +37,7 @@ end module Make - (Domain: Abstract_domain.Internal) + (Domain: Abstract_domain.Leaf) (Convert : Conversion with type internal_value := Domain.value and type internal_location := Domain.location) = struct @@ -45,7 +45,8 @@ module Make include (Domain : Datatype.S_with_collections with type t = Domain.t) include (Domain : Abstract_domain.Lattice with type state = Domain.state) - let structure = Domain.structure + let structure = Abstract.Domain.Leaf (Domain.key, (module Domain)) + let log_category = Domain.log_category type value = Convert.extended_value diff --git a/src/plugins/value/domains/domain_lift.mli b/src/plugins/value/domains/domain_lift.mli index 9e16a8a292ee65d5fd7ff670ac2e9228b9180ba1..9ed356565906f71c2c7aace94cb44fc0e9f5ad9b 100644 --- a/src/plugins/value/domains/domain_lift.mli +++ b/src/plugins/value/domains/domain_lift.mli @@ -36,10 +36,10 @@ end module Make - (Domain: Abstract_domain.Internal) + (Domain: Abstract_domain.Leaf) (Convert : Conversion with type internal_value := Domain.value and type internal_location := Domain.location) - : Abstract_domain.Internal with type state = Domain.state + : Abstract.Domain.Internal with type state = Domain.state and type value = Convert.extended_value and type location = Convert.extended_location and type origin = Domain.origin diff --git a/src/plugins/value/domains/domain_product.ml b/src/plugins/value/domains/domain_product.ml index e596deec5d4fb9c3ec0864d3e1db015137fa16de..1985b6c173ad631b55d0401c0bf67494861cf831 100644 --- a/src/plugins/value/domains/domain_product.ml +++ b/src/plugins/value/domains/domain_product.ml @@ -28,8 +28,8 @@ let product_category = Value_parameters.register_category "domain_product" module Make (Value: Abstract_value.S) - (Left: Abstract_domain.Internal with type value = Value.t) - (Right: Abstract_domain.Internal with type value = Left.value + (Left: Abstract.Domain.Internal with type value = Value.t) + (Right: Abstract.Domain.Internal with type value = Left.value and type location = Left.location) = struct @@ -51,7 +51,7 @@ module Make (struct let module_name = name end) type state = t - let structure = Abstract_domain.Node (Left.structure, Right.structure) + let structure = Abstract.Domain.Node (Left.structure, Right.structure) let log_category = product_category diff --git a/src/plugins/value/domains/domain_product.mli b/src/plugins/value/domains/domain_product.mli index c883a94ba8d1cb26816c742f8c8bf9a5bbe8532c..859988e255221878be47fd1ef9fc7836ca81e6a6 100644 --- a/src/plugins/value/domains/domain_product.mli +++ b/src/plugins/value/domains/domain_product.mli @@ -24,10 +24,10 @@ val product_category: Value_parameters.category module Make (Value: Abstract_value.S) - (Left: Abstract_domain.Internal with type value = Value.t) - (Right: Abstract_domain.Internal with type value = Left.value + (Left: Abstract.Domain.Internal with type value = Value.t) + (Right: Abstract.Domain.Internal with type value = Left.value and type location = Left.location) - : Abstract_domain.Internal with type value = Value.t + : Abstract.Domain.Internal with type value = Value.t and type location = Left.location and type state = Left.state * Right.state diff --git a/src/plugins/value/domains/equality/equality_domain.ml b/src/plugins/value/domains/equality/equality_domain.ml index 7ccb02c97211ab9dfbf100b5cf16abd9c45358d0..7186aaebe57942d239821101d28e1f9770848930 100644 --- a/src/plugins/value/domains/equality/equality_domain.ml +++ b/src/plugins/value/domains/equality/equality_domain.ml @@ -122,9 +122,8 @@ module Internal = struct type state = t let name = "Equality domain" - let key = Structure.Key_Domain.create_key "equality_domain" - let structure : t Abstract_domain.structure = Abstract_domain.Leaf key let log_category = dkey + let key = Structure.Key_Domain.create_key "equality_domain" type equalities = Equality.Set.t let project (t, _, _) = t @@ -180,13 +179,13 @@ module Store = Domain_store.Make (Internal) (* ------------------------- Abstract Domain -------------------------------- *) module Make - (Value : Abstract_value.External) + (Value : Abstract.Value.External) = struct include Internal module Store = Store - let get_cvalue = Value.get Main_values.cvalue_key + let get_cvalue = Value.get Main_values.CVal.key type value = Value.t type location = Precise_locs.precise_location @@ -218,7 +217,7 @@ module Make let c = get v in if Cvalue.V.is_imprecise c then let c' = Cvalue.V.topify_with_origin Origin.top c in - Value.set Main_values.cvalue_key c' v + Value.set Main_values.CVal.key c' v else v let coop_eval oracle equalities atom_src = diff --git a/src/plugins/value/domains/equality/equality_domain.mli b/src/plugins/value/domains/equality/equality_domain.mli index 6f6d041654125ff27303bcd95cd853297b8ba836..1242e9d2e9cc9af841e56d5ffcad96c5c0595747 100644 --- a/src/plugins/value/domains/equality/equality_domain.mli +++ b/src/plugins/value/domains/equality/equality_domain.mli @@ -31,10 +31,9 @@ type call_init_state = | ISEmpty (** completely empty state, without impact on Memexec. *) -module Make (Value : Abstract_value.External) : sig - include Abstract_domain.Internal with type value = Value.t - and type location = Precise_locs.precise_location - val key : t Abstract_domain.key +module Make (Value : Abstract.Value.External) : sig + include Abstract_domain.Leaf with type value = Value.t + and type location = Precise_locs.precise_location val pretty_debug : Format.formatter -> t -> unit diff --git a/src/plugins/value/domains/gauges/gauges_domain.ml b/src/plugins/value/domains/gauges/gauges_domain.ml index 1af3127519259cc44ffd7db880c28f39dc8983da..e45fc726212b250492260e4c551bc5c1bed3dea4 100644 --- a/src/plugins/value/domains/gauges/gauges_domain.ml +++ b/src/plugins/value/domains/gauges/gauges_domain.ml @@ -1120,7 +1120,7 @@ end let dkey = Value_parameters.register_category "d-gauges" -module D_Impl : Abstract_domain.S_with_Structure +module D_Impl : Abstract_domain.S with type state = G.t and type value = Cvalue.V.t and type location = Precise_locs.precise_location @@ -1132,8 +1132,6 @@ module D_Impl : Abstract_domain.S_with_Structure include G let name = "Gauges domain" - - let structure = Abstract_domain.Void let log_category = dkey let empty _ = G.empty diff --git a/src/plugins/value/domains/gauges/gauges_domain.mli b/src/plugins/value/domains/gauges/gauges_domain.mli index a1609d838a046745346cd36f02e063314057b88a..f51fdfbc660171bd5485c37869384790319e43e1 100644 --- a/src/plugins/value/domains/gauges/gauges_domain.mli +++ b/src/plugins/value/domains/gauges/gauges_domain.mli @@ -23,6 +23,6 @@ (** Gauges domain ("Arnaud Venet: The Gauge Domain: Scalable Analysis of Linear Inequality Invariants. CAV 2012") *) -module D: Abstract_domain.Internal +module D: Abstract_domain.Leaf with type value = Cvalue.V.t and type location = Precise_locs.precise_location diff --git a/src/plugins/value/domains/inout_domain.ml b/src/plugins/value/domains/inout_domain.ml index 12ba3cd152852bbd7ea98e40b0921ae2110bc5a6..1a5a4888c93f0f23d46045a7048f47755e2075b2 100644 --- a/src/plugins/value/domains/inout_domain.ml +++ b/src/plugins/value/domains/inout_domain.ml @@ -204,8 +204,6 @@ module Transfer = struct end -let key = Structure.Key_Domain.create_key "inout domain" - module Internal (*: Domain_builder.InputDomain with type state = inout @@ -221,7 +219,7 @@ module Internal include Abstract_domain.Lattice with type state := state end) - let structure : t Abstract_domain.structure = Abstract_domain.Leaf key + let name = "inout" let log_category = Value_parameters.register_category "d-inout" let enter_scope _kf _vars state = state diff --git a/src/plugins/value/domains/inout_domain.mli b/src/plugins/value/domains/inout_domain.mli index 0304f94f6900c3178afd03ca5c1d3534896a70a6..f759f59bfe6bff258657a4623bfdec01048222e4 100644 --- a/src/plugins/value/domains/inout_domain.mli +++ b/src/plugins/value/domains/inout_domain.mli @@ -22,8 +22,6 @@ (** Computation of inputs of outputs. *) -module D: Abstract_domain.Internal +module D: Abstract_domain.Leaf with type value = Cvalue.V.t and type location = Precise_locs.precise_location - -val key: D.t Abstract_domain.key diff --git a/src/plugins/value/domains/numerors/numerors_domain.ko.ml b/src/plugins/value/domains/numerors/numerors_domain.ko.ml deleted file mode 100644 index eb6bc8b9a4fd68b544826004a66bc62dc4b3f43d..0000000000000000000000000000000000000000 --- a/src/plugins/value/domains/numerors/numerors_domain.ko.ml +++ /dev/null @@ -1,39 +0,0 @@ -(**************************************************************************) -(* *) -(* This file is part of Frama-C. *) -(* *) -(* Copyright (C) 2007-2019 *) -(* CEA (Commissariat à l'énergie atomique et aux énergies *) -(* alternatives) *) -(* *) -(* you can redistribute it and/or modify it under the terms of the GNU *) -(* Lesser General Public License as published by the Free Software *) -(* Foundation, version 2.1. *) -(* *) -(* It is distributed in the hope that it will be useful, *) -(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) -(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) -(* GNU Lesser General Public License for more details. *) -(* *) -(* See the GNU Lesser General Public License version 2.1 *) -(* for more details (enclosed in the file licenses/LGPLv2.1). *) -(* *) -(**************************************************************************) - -#24 "src/plugins/value/domains/numerors/numerors_domain.ko.ml" - -type value -type location = Precise_locs.precise_location -let value_key = Structure.Key_Value.create_key "dummy_numerors_values" - -let ok = false - -let abort () = - Value_parameters.abort - "The numerors domain has been requested but is not available, as Frama-C \ - did not found the MPFR library. The analysis is aborted." - -let add_numerors_value _ = abort () -let numerors_domain = abort - -let reduce_error _ = fun v -> v diff --git a/src/plugins/value/domains/numerors/numerors_domain.ok.ml b/src/plugins/value/domains/numerors/numerors_domain.ml similarity index 57% rename from src/plugins/value/domains/numerors/numerors_domain.ok.ml rename to src/plugins/value/domains/numerors/numerors_domain.ml index cf8e73a78c435b8f993f61ab80c07057b10d60d4..6295adc0eed64e7d4495b8c1dc62ed8aba6ec0cf 100644 --- a/src/plugins/value/domains/numerors/numerors_domain.ok.ml +++ b/src/plugins/value/domains/numerors/numerors_domain.ml @@ -20,17 +20,10 @@ (* *) (**************************************************************************) -#24 "src/plugins/value/domains/numerors/numerors_domain.ok.ml" - open Eval open Cil_types -type value = Numerors_value.t -type location = Precise_locs.precise_location -let value_key = Numerors_value.error_key - -let ok = true - +(* The numerors values, plus some builtin functions. *) module Numerors_Value = struct include Numerors_value @@ -87,61 +80,7 @@ module Numerors_Value = struct ] end -let add_numerors_value (module Value: Abstract_value.Internal) = - let module External_Value = Structure.Open (Structure.Key_Value) (Value) in - let module V = struct - include Value_product.Make (Value) (Numerors_value) - - let forward_cast = match External_Value.get Main_values.cvalue_key with - | None -> forward_cast - | Some get_cvalue -> - fun ~src_type ~dst_type (value, num) -> - forward_cast ~src_type ~dst_type (value, num) >>-: fun (value', num) -> - let num = match src_type, dst_type with - | Eval_typ.TSInt _, Eval_typ.TSFloat fkind -> - begin - try - let cvalue = get_cvalue value in - let ival = Cvalue.V.project_ival cvalue in - match Ival.min_and_max ival with - | Some min, Some max -> - let min, max = Integer.to_int min, Integer.to_int max in - let prec = Numerors_utils.Precisions.of_fkind fkind in - Numerors_value.of_ints ~prec min max - | _, _ -> num - (* Integer.to_int may fail for too big integers. *) - with Cvalue.V.Not_based_on_null | Z.Overflow -> num - end - | _, _ -> num - in - value', num - end in - (module V: Abstract_value.Internal) - -let reduce_error (type v) (module V: Abstract_value.External with type t = v) = - match V.get Numerors_value.error_key, V.get Main_values.cvalue_key with - | Some get_error, Some get_cvalue -> - begin - let set_error = V.set Numerors_value.error_key in - fun t -> - let cvalue = get_cvalue t in - try - let ival = Cvalue.V.project_ival cvalue in - match ival with - | Ival.Float fval -> - begin - let error = get_error t in - let error = Numerors_value.reduce fval error in - match error with - | `Value error -> set_error error t - | `Bottom -> t (* TODO: we should be able to reduce to bottom. *) - end - | _ -> t - with Cvalue.V.Not_based_on_null -> t - end - | _, _ -> fun x -> x - - +(* The numerors domain: a simple memory over the numerors value. *) module Domain = struct module Name = struct let name = "numerors" end include Simple_memory.Make_Domain (Name) (Numerors_Value) @@ -157,7 +96,72 @@ module Domain = struct | _, _ -> () end -let numerors_domain () = - Value_parameters.warning "The numerors domain is experimental."; - (module Domain: Abstract_domain.Internal with type value = value - and type location = location) +(* Reduced product between the cvalue values and the numerors values. *) +let reduce_error cvalue error = + try + let ival = Cvalue.V.project_ival cvalue in + match ival with + | Ival.Float fval -> + begin + match Numerors_value.reduce fval error with + | `Value error -> cvalue, error + | `Bottom -> cvalue, error (* TODO: we should be able to reduce to bottom. *) + end + | _ -> cvalue, error + with Cvalue.V.Not_based_on_null -> cvalue, error + +(* Reduction of the numerors value resulting from a cast from int to float type, + using the cvalue component of value abstractions. *) +let reduce_cast (module Abstract: Abstractions.S) = + let module Val = struct + include Abstract.Val + + (* Redefines the [forward_cast] function of the value component. *) + let forward_cast = + (* If cvalue or numerors do not belong to the abstraction, no reduction: + the [forward_cast] function is unchanged. *) + match get Main_values.CVal.key, mem Numerors_value.key with + | None, _ | _, false -> forward_cast + | Some get_cvalue, true -> + (* Otherwise, applies the [forward_cast] function, but updates the + numerors component of the result. *) + fun ~src_type ~dst_type value -> + forward_cast ~src_type ~dst_type value >>-: fun result -> + match src_type, dst_type with + | Eval_typ.TSInt _, Eval_typ.TSFloat fkind -> + begin + try + let cvalue = get_cvalue value in + let ival = Cvalue.V.project_ival cvalue in + match Ival.min_and_max ival with + | Some min, Some max -> + let min, max = Integer.to_int min, Integer.to_int max in + let prec = Numerors_utils.Precisions.of_fkind fkind in + let num = Numerors_value.of_ints ~prec min max in + set Numerors_value.key num result + | _, _ -> result + (* Integer.to_int may fail for too big integers. *) + with Cvalue.V.Not_based_on_null | Z.Overflow -> result + end + | _, _ -> result + end in + (module struct + module Val = Val + module Loc = Abstract.Loc + module Dom = Abstract.Dom + end: Abstractions.S) + +(* Register the domain as an Eva abstractions. *) +let () = + let open Abstractions in + let domain = + { name = "numerors"; + priority = 0; + values = Single (module Numerors_value); + domain = Domain (module Domain); } + in + let reduced_product = Main_values.CVal.key, Numerors_value.key, reduce_error in + register ~enable:Value_parameters.NumerorsDomain.get domain; + register_value_reduction reduced_product; + register_hook reduce_cast; + Value_parameters.register_numerors () diff --git a/src/plugins/value/domains/numerors/numerors_domain.mli b/src/plugins/value/domains/numerors/numerors_domain.mli index d08ef39909623588ccb4c7582daf7c7a05bdce2a..6fcd35b31eed7cff62e5bdbbda30383c54f47cfc 100644 --- a/src/plugins/value/domains/numerors/numerors_domain.mli +++ b/src/plugins/value/domains/numerors/numerors_domain.mli @@ -20,30 +20,7 @@ (* *) (**************************************************************************) -type value -type location = Precise_locs.precise_location -val value_key : value Structure.Key_Value.k - -(** True if the numerors domain is available; - False if the MPFR library has not been found. *) -val ok: bool - -(** Functions used by the engine to build numerors abstractions. *) - -(** Builds the product between a given value module and the numerors value - module. If the given value module contains Cvalue, uses cvalues to reduce - numerors values on casts from integer to floating-point values. - Fails if numerors domain is not available. *) -val add_numerors_value: - (module Abstract_value.Internal) -> (module Abstract_value.Internal) - -(* From a given abstract value product, creates the reduction function that - reduces numerors values by using cvalues. Returns the identity if the given - value product does not contain numerors and cvalue componants. *) -val reduce_error: - (module Abstract_value.External with type t = 'v) -> ('v -> 'v) - -(** Returns the numerors domain module, if available. Fails otherwise. *) -val numerors_domain: - unit -> (module Abstract_domain.Internal with type value = value - and type location = location) +(** Numerors domain: computes over-approximations of the rounding errors bounds + of floating-point computations. + Nothing is exported: the domain is registered as an analysis abstraction + in the Eva engine, enabled by the -eva-numerors-domain option. *) diff --git a/src/plugins/value/domains/offsm_domain.ml b/src/plugins/value/domains/offsm_domain.ml index 8ab4ee60ca741522d565be563559c1224d23022d..f491384582b905f2aba39ffa65dc80f073344669 100644 --- a/src/plugins/value/domains/offsm_domain.ml +++ b/src/plugins/value/domains/offsm_domain.ml @@ -103,7 +103,6 @@ module Internal : Domain_builder.InputDomain end) let name = "Bitwise domain" - let structure = Abstract_domain.Void let log_category = dkey let empty _ = Memory.empty_map diff --git a/src/plugins/value/domains/offsm_domain.mli b/src/plugins/value/domains/offsm_domain.mli index 4567fc14d3f21c1ad2db640e9264fe6ec387e4cb..8833d4b88cb93b0134e3239aa139a3c6a34585a5 100644 --- a/src/plugins/value/domains/offsm_domain.mli +++ b/src/plugins/value/domains/offsm_domain.mli @@ -20,6 +20,6 @@ (* *) (**************************************************************************) -module D : Abstract_domain.Internal +module D : Abstract_domain.Leaf with type value = Offsm_value.offsm_or_top and type location = Precise_locs.precise_location diff --git a/src/plugins/value/domains/printer_domain.mli b/src/plugins/value/domains/printer_domain.mli index 5355cebbd9cbf82b76690098e670e0af76855c9c..febfc6902d6a8cdf0d0bee4a199bbdadd5cc094d 100644 --- a/src/plugins/value/domains/printer_domain.mli +++ b/src/plugins/value/domains/printer_domain.mli @@ -23,5 +23,5 @@ (** An abstract domain built on top of the Simpler_domains.Simple_Cvalue interface that just prints the transfer functions called by the engine during an analysis. *) -include Abstract_domain.Internal with type value = Cvalue.V.t - and type location = Precise_locs.precise_location +include Abstract_domain.Leaf with type value = Cvalue.V.t + and type location = Precise_locs.precise_location diff --git a/src/plugins/value/domains/sign_domain.mli b/src/plugins/value/domains/sign_domain.mli index fafc9f18c67cf1cd72ee5d88375dfce1631f8fe6..b32803feb652aad71ea799b02aff6a7c733f6b40 100644 --- a/src/plugins/value/domains/sign_domain.mli +++ b/src/plugins/value/domains/sign_domain.mli @@ -22,5 +22,5 @@ (** Abstraction of the sign of integer variables. *) -include Abstract_domain.Internal with type value = Sign_value.t - and type location = Precise_locs.precise_location +include Abstract_domain.Leaf with type value = Sign_value.t + and type location = Precise_locs.precise_location diff --git a/src/plugins/value/domains/simple_memory.ml b/src/plugins/value/domains/simple_memory.ml index f312b589f11a835903ac4080566ce7f14b81df3a..ea1757685829577ec77aa94c1c1de8ff79dc8ce2 100644 --- a/src/plugins/value/domains/simple_memory.ml +++ b/src/plugins/value/domains/simple_memory.ml @@ -188,9 +188,6 @@ module Make_Internal (Info: sig val name: string end) (Value: Value) = struct type value = Value.t type location = Precise_locs.precise_location - let key = Structure.Key_Domain.create_key (Info.name ^ " domain") - let structure : t Abstract_domain.structure = Abstract_domain.Leaf key - let log_category = Value_parameters.register_category ("d-" ^ Info.name) let widen _kf _stmt = widen diff --git a/src/plugins/value/domains/simple_memory.mli b/src/plugins/value/domains/simple_memory.mli index e45eef5cb3a61dcb648a8934330ceabd2d36552f..0ea8a003a607d3271ff50d8c4909948c933b520b 100644 --- a/src/plugins/value/domains/simple_memory.mli +++ b/src/plugins/value/domains/simple_memory.mli @@ -106,8 +106,8 @@ module Make_Domain (Value: Value) : sig - include Abstract_domain.Internal with type value = Value.t - and type location = Precise_locs.precise_location + include Abstract_domain.Leaf with type value = Value.t + and type location = Precise_locs.precise_location include S with type t := t and type value := Value.t diff --git a/src/plugins/value/domains/symbolic_locs.ml b/src/plugins/value/domains/symbolic_locs.ml index 42db4cd7cb58a9c6b6cd3cd75b24f28ab2bd0149..00220370476099169b87412b86f2b397e6574c2f 100644 --- a/src/plugins/value/domains/symbolic_locs.ml +++ b/src/plugins/value/domains/symbolic_locs.ml @@ -472,7 +472,6 @@ module Internal : Domain_builder.InputDomain end) let name = "Symbolic locations domain" - let structure = Abstract_domain.Void let log_category = dkey let empty _ = Memory.empty_map diff --git a/src/plugins/value/domains/symbolic_locs.mli b/src/plugins/value/domains/symbolic_locs.mli index 06cda3ce5eb47f2d1ac33fdfe85205c3dbb1afbb..7cebf7b9f4cb6083bf3625b520be6bf5c1e30ae1 100644 --- a/src/plugins/value/domains/symbolic_locs.mli +++ b/src/plugins/value/domains/symbolic_locs.mli @@ -23,6 +23,6 @@ (** Domain that store information on non-precise l-values such as [t[i]] or [*p] when [i] or [p] is not exact. *) -module D: Abstract_domain.Internal +module D: Abstract_domain.Leaf with type value = Cvalue.V.t and type location = Precise_locs.precise_location diff --git a/src/plugins/value/domains/traces_domain.ml b/src/plugins/value/domains/traces_domain.ml index 68f7b320300808fd20c819154f7fcd6d4b8e4705..f7d5946d2dd0477f135ef6c82b6f6190410c1156 100644 --- a/src/plugins/value/domains/traces_domain.ml +++ b/src/plugins/value/domains/traces_domain.ml @@ -846,8 +846,6 @@ let rec complete_graph (graph:Graph.t) = ) graph Graph.empty -let key = Structure.Key_Domain.create_key "traces domain" - module Internal = struct type nonrec state = state type value = Cvalue.V.t @@ -858,7 +856,6 @@ module Internal = struct include Abstract_domain.Lattice with type state := state end) - let structure : t Abstract_domain.structure = Abstract_domain.Leaf key let log_category = Value_parameters.register_category "d-traces" type origin = unit @@ -1271,8 +1268,7 @@ let output_dot filename state = close_out out module D = struct - include Internal - module Store = Domain_store.Make(Internal) + include Domain_builder.Complete (Internal) let post_analysis state = let return_stmt = Kernel_function.find_return (fst (Globals.entry_point ())) in diff --git a/src/plugins/value/domains/traces_domain.mli b/src/plugins/value/domains/traces_domain.mli index 7319b2f20bc6c107e0e135a976e75355c26e0a7c..a1c57a5359d505bcb8ba41a06b9ab4d7003f649f 100644 --- a/src/plugins/value/domains/traces_domain.mli +++ b/src/plugins/value/domains/traces_domain.mli @@ -71,7 +71,7 @@ val current: state -> loops val globals: state -> Cil_types.varinfo list val entry_formals: state -> Cil_types.varinfo list -module D: Abstract_domain.Internal +module D: Abstract_domain.Leaf with type value = Cvalue.V.t and type location = Precise_locs.precise_location and type state = state diff --git a/src/plugins/value/domains/unit_domain.ml b/src/plugins/value/domains/unit_domain.ml index 4bb14526c7b277ba0348fd36954e862c6d997ab4..e78644f8c489b4125db88289516e89dec38bc0f3 100644 --- a/src/plugins/value/domains/unit_domain.ml +++ b/src/plugins/value/domains/unit_domain.ml @@ -28,8 +28,8 @@ module Static = struct type state = t let name = "Unit domain" - let structure = Abstract_domain.Void let log_category = log_key + let structure = Abstract.Domain.Unit let top = () let is_included _ _ = true diff --git a/src/plugins/value/domains/unit_domain.mli b/src/plugins/value/domains/unit_domain.mli index 03a18359466383b2b457973f30e5d872e498228f..e1ed4495741e0e69942ef91292998f274f08b9c9 100644 --- a/src/plugins/value/domains/unit_domain.mli +++ b/src/plugins/value/domains/unit_domain.mli @@ -23,7 +23,7 @@ module Make (Value: Abstract_value.S) (Loc: Abstract_location.S) - : Abstract_domain.Internal with type state = unit + : Abstract.Domain.Internal with type state = unit and type value = Value.t and type location = Loc.location diff --git a/src/plugins/value/engine/abstractions.ml b/src/plugins/value/engine/abstractions.ml index 256fe3fd89b4c89ca13976f788b4c4ecccde0aca..5781d60bf7672faf0129790ab98f89cde419dd68 100644 --- a/src/plugins/value/engine/abstractions.ml +++ b/src/plugins/value/engine/abstractions.ml @@ -20,583 +20,424 @@ (* *) (**************************************************************************) -(* Configuration of the abstract domain. *) - -type config = { - cvalue : bool; - equalities : bool; - symbolic_locs : bool; - bitwise : bool; - gauges : bool; - apron_oct : bool; - apron_box : bool; - polka_loose : bool; - polka_strict : bool; - polka_equalities : bool; - inout: bool; - signs: bool; - printer: bool; - numerors: bool; - traces: bool; -} - -let configure () = { - cvalue = Value_parameters.CvalueDomain.get (); - equalities = Value_parameters.EqualityDomain.get (); - symbolic_locs = Value_parameters.SymbolicLocsDomain.get (); - bitwise = Value_parameters.BitwiseOffsmDomain.get (); - gauges = Value_parameters.GaugesDomain.get (); - apron_oct = Value_parameters.ApronOctagon.get (); - apron_box = Value_parameters.ApronBox.get (); - polka_loose = Value_parameters.PolkaLoose.get (); - polka_strict = Value_parameters.PolkaStrict.get (); - polka_equalities = Value_parameters.PolkaEqualities.get (); - inout = Value_parameters.InoutDomain.get (); - signs = Value_parameters.SignDomain.get (); - printer = Value_parameters.PrinterDomain.get (); - numerors = Value_parameters.NumerorsDomain.get (); - traces = Value_parameters.TracesDomain.get (); -} - -let default_config = configure () - -let legacy_config = { - cvalue = true; - equalities = false; - symbolic_locs = false; - bitwise = false; - gauges = false; - apron_oct = false; - apron_box = false; - polka_loose = false; - polka_strict = false; - polka_equalities = false; - inout = false; - signs = false; - printer = false; - numerors = false; - traces = false; -} +(* --- Registration types --------------------------------------------------- *) -module type Value = sig - include Abstract_value.External - val reduce : t -> t +type 'v value = + | Single of (module Abstract_value.Leaf with type t = 'v) + | Struct of 'v Abstract.Value.structure + +type precise_loc = Precise_locs.precise_location + +module type leaf_domain = Abstract_domain.Leaf with type location = precise_loc + +module type domain_functor = + functor (Value: Abstract.Value.External) -> + (leaf_domain with type value = Value.t) + +type 'v domain = + | Domain: (module leaf_domain with type value = 'v) -> 'v domain + | Functor: (module domain_functor) -> _ domain + +type 'v abstraction = + { name: string; + priority: int; + values: 'v value; + domain: 'v domain; } + +(* --- Config and registration ---------------------------------------------- *) + +module Config = struct + type flag = Flag: 'v abstraction -> flag + + module Flag = struct + type t = flag + + (* Flags are sorted by increasing priority order, and then by name. *) + let compare (Flag f1) (Flag f2) = + let c = Datatype.Int.compare f1.priority f2.priority in + if c <> 0 then c else Datatype.String.compare f1.name f2.name + end + + include Set.Make (Flag) + + type dynamic = Dynamic: (unit -> 'a option) * ('a -> 'v abstraction) -> dynamic + + let abstractions = ref [] + let dynamic_abstractions : dynamic list ref = ref [] + + let register ~enable abstraction = + abstractions := (enable, Flag abstraction) :: !abstractions + + let dynamic_register ~configure ~make = + dynamic_abstractions := Dynamic (configure, make) :: !dynamic_abstractions + + let configure () = + let aux config (enable, flag) = + if enable () then add flag config else config + in + let config = List.fold_left aux empty !abstractions in + let aux config (Dynamic (configure, make)) = + match configure () with + | None -> config + | Some c -> add (Flag (make c)) config + in + List.fold_left aux config !dynamic_abstractions + + (* --- Register default abstractions -------------------------------------- *) + + let create ~enable abstract = register ~enable abstract; Flag abstract + let create_domain priority name enable values domain = + create ~enable + { name; priority; values = Single values; domain = Domain domain } + + open Value_parameters + + (* Register standard domains over cvalues. *) + let make rank name enable = + create_domain rank name enable (module Main_values.CVal) + + let cvalue = make 9 "cvalue" CvalueDomain.get (module Cvalue_domain.State) + let gauges = make 6 "gauges" GaugesDomain.get (module Gauges_domain.D) + let inout = make 5 "inout" InoutDomain.get (module Inout_domain.D) + let traces = make 2 "traces" TracesDomain.get (module Traces_domain.D) + let printer = make 2 "printer" PrinterDomain.get (module Printer_domain) + let symbolic_locations = + make 7 "symbolic_locations" SymbolicLocsDomain.get (module Symbolic_locs.D) + + let sign = + create_domain 4 "sign" SignDomain.get + (module Sign_value) (module Sign_domain) + + let bitwise = + create_domain 3 "bitwise" BitwiseOffsmDomain.get + (module Offsm_value.Offsm) (module Offsm_domain.D) + + let equality_domain = + { name = "equality"; + priority = 8; + values = Struct Abstract.Value.Unit; + domain = Functor (module Equality_domain.Make); } + let equality = create ~enable:EqualityDomain.get equality_domain + + (* --- Default and legacy configurations ---------------------------------- *) + + let default = configure () + let legacy = singleton cvalue end -module type S = sig - module Val : Value - 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 +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 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 +module Leaf_Location (Loc: Abstract_location.Leaf) = struct + include Loc + let structure = Abstract.Location.Leaf (Loc.key, (module Loc)) end -(* -------------------------------------------------------------------------- *) -(* Value Abstraction *) -(* -------------------------------------------------------------------------- *) +module Leaf_Domain (D: Abstract_domain.Leaf) = struct + include D + let structure = Abstract.Domain.Leaf (D.key, (module D)) +end -module type V = sig - include Abstract_value.External - val structure : t Abstract_value.structure +module type Acc = sig + module Val : Abstract.Value.External + module Loc : Abstract.Location.Internal with type value = Val.t + and type location = precise_loc + module Dom : Abstract.Domain.Internal with type value = Val.t + and type location = Loc.location end -module CVal = struct - include Main_values.CVal - include Structure.Open (Structure.Key_Value) (Main_values.CVal) +module Internal_Value = struct + open Abstract.Value + + 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 add_value_structure value internal = + let rec aux: type v. (module Internal) -> v structure -> (module Internal) = + fun value -> function + | Leaf (key, v) -> add_value_leaf value (V (key, v)) + | Node (s1, s2) -> aux (aux value s1) s2 + | Unit -> value + in + aux value internal + + let build_values config initial_value = + let build (Config.Flag abstraction) acc = + match 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 Convert + (Value: Abstract.Value.External) + (Struct: sig type v val s : v value end) + = struct + + let structure = match Struct.s with + | Single (module V) -> Abstract.Value.Leaf (V.key, (module V)) + | Struct s -> s + + type extended_value = Value.t + + let replace_val = + 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) + | Unit -> fun () value -> value + in + set structure + + let extend_val v = replace_val v Value.top + + let restrict_val = + let rec get: type v. v structure -> Value.t -> v = function + | Leaf (key, _) -> Extlib.the (Value.get key) + | Node (s1, s2) -> + let get1 = get s1 and get2 = get s2 in + fun v -> get1 v, get2 v + | Unit -> fun _ -> () + in + get structure + + type extended_location = Main_locations.PLoc.location + + let restrict_loc = fun x -> x + let extend_loc = fun x -> x + end end -let has_apron config = - config.apron_oct || config.apron_box || config.polka_equalities - || config.polka_loose || config.polka_strict - -(* The apron domains relies on a specific interval abstraction to communicate - with other domains. This function adds the intervals to the current [value] - abstraction. These intervals carry the same information as the cvalue - abstractions (if they are enabled). Do not display the intervals in the GUI - in this case. *) -let add_apron_value config value = - let module Left = ((val value: Abstract_value.Internal)) in - let module V = struct - include Value_product.Make (Left) (Main_values.Interval) - let pretty_typ = - if config.cvalue - then fun fmt typ (left, _right) -> Left.pretty_typ fmt typ left - else pretty_typ - end in - (module V: Abstract_value.Internal) - -let open_value_abstraction value = - let module Value = (val value : Abstract_value.Internal) in - (module struct - include Value - include Structure.Open (Structure.Key_Value) (Value) - end : V) - -let build_value config = - let value = - if config.bitwise - then (module Offsm_value.CvalueOffsm : Abstract_value.Internal) - else (module Main_values.CVal : Abstract_value.Internal) - in - let value = - if config.signs - then - let module V = Value_product.Make ((val value)) (Sign_value) in - (module V: Abstract_value.Internal) - else value - in - let value = - if config.numerors - then Numerors_domain.add_numerors_value value - else value +(* --- Building domain abstractions ----------------------------------------- *) + +module type internal_loc = + Abstract.Location.Internal with type location = precise_loc +module type internal_domain = + Abstract.Domain.Internal with type location = precise_loc + +let eq_value: + type a b. a Abstract.Value.structure -> b value -> (a,b) Structure.eq option + = fun structure -> function + | Struct s -> Abstract.Value.eq_structure structure s + | Single (module V) -> + match structure with + | Abstract.Value.Leaf (key, _) -> Abstract.Value.eq_type key V.key + | _ -> None + +let add_domain (type v) (abstraction: v abstraction) (module Acc: Acc) = + let domain : (module internal_domain with type value = Acc.Val.t) = + match abstraction.domain with + | Functor make -> + let module Make = (val make: domain_functor) in + (module Leaf_Domain (Make (Acc.Val))) + | Domain domain -> + match eq_value Acc.Val.structure abstraction.values with + | Some Structure.Eq -> + let module Domain = (val domain) in + (module Leaf_Domain (Domain)) + | None -> + let module Domain = (val domain : leaf_domain with type value = v) in + let module Struct = struct + type v = Domain.value + let s = abstraction.values + end in + let module Convert = Internal_Value.Convert (Acc.Val) (Struct) in + (module Domain_lift.Make (Domain) (Convert)) in - let value = - if has_apron config - then add_apron_value config value - else value + let domain : (module internal_domain with type value = Acc.Val.t) = + 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 - open_value_abstraction value - -(* Builds a module conversion from a generic external value to a key. *) -module Convert - (Value : Abstract_value.External) - (K : sig type v val key : v Abstract_value.key end) -= struct - type extended_value = Value.t - type extended_location = Main_locations.PLoc.location + (module struct + module Val = Acc.Val + module Loc = Acc.Loc + module Dom = (val domain) + end : Acc) - let extend_val = - let set = Value.set K.key in - fun v -> set v Value.top +let build_domain config abstract = + let build (Config.Flag abstraction) acc = add_domain 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 - let replace_val = Value.set K.key - let restrict_val = match Value.get K.key with - | None -> assert false - | Some get -> get +(* --- Value reduced product ----------------------------------------------- *) - let restrict_loc = fun x -> x - let extend_loc = fun x -> x +module type Value = sig + include Abstract.Value.External + val reduce : t -> t end - -(* -------------------------------------------------------------------------- *) -(* Cvalue Domain *) -(* -------------------------------------------------------------------------- *) - -(* Abstractions needed for the analysis: value, location and domain. *) -module type Abstract = sig - module Val : V - module Loc : Abstract_location.Internal with type value = Val.t - and type location = Precise_locs.precise_location - module Dom : Abstract_domain.Internal with type value = Val.t +module type S = sig + module Val : Value + 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 -let default_root_abstraction config = - if config.cvalue - then - (module struct - module Val = CVal - module Loc = Main_locations.PLoc - module Dom = Cvalue_domain.State - end : Abstract) - else - (module struct - module Val = CVal - module Loc = Main_locations.PLoc - module Dom = Unit_domain.Make (Val) (Loc) - end : Abstract) - -let build_root_abstraction config value = - let module Val = (val value : V) in - let module K = struct - type v = Cvalue.V.t - let key = Main_values.cvalue_key - end in - let module Conv = Convert (Val) (K) in - if config.cvalue - then - (module struct - module Val = Val - module Loc = Location_lift.Make (Main_locations.PLoc) (Conv) - module Dom = Domain_lift.Make (Cvalue_domain.State) (Conv) - end : Abstract) - else - (module struct - module Val = Val - module Loc = Location_lift.Make (Main_locations.PLoc) (Conv) - module Dom = Unit_domain.Make (Val) (Loc) - end : Abstract) - - -(* -------------------------------------------------------------------------- *) -(* Apron Domains *) -(* -------------------------------------------------------------------------- *) - -let add_apron_domain abstract apron = - let module Abstract = (val abstract: Abstract) in - let module K = struct - type v = Main_values.Interval.t - let key = Main_values.interval_key - end in - let module Conv = Convert (Abstract.Val) (K) in - let module Apron = Domain_lift.Make ((val apron : Apron_domain.S)) (Conv) in - (module struct - module Val = Abstract.Val - module Loc = Abstract.Loc - module Dom = Domain_product.Make (Abstract.Val) (Abstract.Dom) (Apron) - end : Abstract) +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 dkey_experimental = Value_parameters.register_category "experimental-ok" -let add_apron_domain abstractions apron = - if not (Value_parameters.is_debug_key_enabled dkey_experimental) then - Value_parameters.warning "The Apron domains binding is experimental."; - if Apron_domain.ok - then add_apron_domain abstractions apron - else - Value_parameters.abort - "Apron domain requested but apron binding not available: analysis aborted." +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 -(* -------------------------------------------------------------------------- *) -(* Equality Domain *) -(* -------------------------------------------------------------------------- *) +let value_reduced_product = ref [] -module CvalueEquality = Equality_domain.Make (CVal) +let register_value_reduction reduced_product = + value_reduced_product := (R reduced_product) :: !value_reduced_product -let add_generic_equalities (module Abstract : Abstract) = - let module EqDom = Equality_domain.Make (Abstract.Val) in - let module Dom = Domain_product.Make (Abstract.Val) (Abstract.Dom) (EqDom) in - (module struct - module Val = Abstract.Val - module Loc = Abstract.Loc - module Dom = Dom - end : Abstract) - -let add_equalities (type v) (module Abstract : Abstract with type Val.t = v) = - match Abstract.Val.structure with - | Structure.Key_Value.Leaf key -> - begin - match Structure.Key_Value.eq_type key Main_values.cvalue_key with - | None -> add_generic_equalities (module Abstract) - | Some Structure.Eq -> - let module Dom = - Domain_product.Make (Abstract.Val) (Abstract.Dom) (CvalueEquality) - in - (module struct - module Val = Abstract.Val - module Loc = Abstract.Loc - module Dom = Dom - end : Abstract) +(* 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 - | _ -> add_generic_equalities (module Abstract) - - -(* -------------------------------------------------------------------------- *) -(* Offsetmap Domain *) -(* -------------------------------------------------------------------------- *) - -let add_offsm abstract = - let module Abstract = (val abstract : Abstract) in - let module K = struct - type v = Offsm_value.offsm_or_top - let key = Offsm_value.offsm_key - end in - let module Conv = Convert (Abstract.Val) (K) in - let module Offsm = Domain_lift.Make (Offsm_domain.D) (Conv) in - let module Dom = Domain_product.Make (Abstract.Val) (Abstract.Dom) (Offsm) in - (module struct - module Val = Abstract.Val - module Loc = Abstract.Loc - module Dom = Dom - end : Abstract) - -(* -------------------------------------------------------------------------- *) -(* Domains on standard locations and values *) -(* -------------------------------------------------------------------------- *) - -module type Standard_abstraction = Abstract_domain.Internal - with type value = Cvalue.V.t - and type location = Precise_locs.precise_location - -let add_standard_domain d abstract = - let module Abstract = (val abstract : Abstract) in - let module K = struct - type v = Cvalue.V.t - let key = Main_values.cvalue_key - end in - let module Conv = Convert (Abstract.Val) (K) in - let module D = (val d: Standard_abstraction) in - let module LD = Domain_lift.Make (D) (Conv) in - let module Dom = Domain_product.Make (Abstract.Val)(Abstract.Dom)(LD) in - (module struct - module Val = Abstract.Val - module Loc = Abstract.Loc - module Dom = Dom - end : Abstract) - -(* List of abstractions registered by other plugins *) -let dynamic_abstractions = ref [] - -let add_dynamic_abstractions abstract = - List.fold_left - (fun d abstract -> add_standard_domain abstract d) - abstract !dynamic_abstractions - -let register_dynamic_abstraction d = - dynamic_abstractions := d :: !dynamic_abstractions - -(* --------------------------------------------------------------------------*) -(* Symbolic locations *) -(* --------------------------------------------------------------------------*) - -let add_symbolic_locs = - add_standard_domain (module Symbolic_locs.D) - -(* -------------------------------------------------------------------------- *) -(* Gauges *) -(* -------------------------------------------------------------------------- *) - -let add_gauges = - add_standard_domain (module Gauges_domain.D) - -(* -------------------------------------------------------------------------- *) -(* Inout *) -(* -------------------------------------------------------------------------- *) - -let add_inout = - add_standard_domain (module Inout_domain.D) - -(* -------------------------------------------------------------------------- *) -(* Sign Domain *) -(* -------------------------------------------------------------------------- *) - -let add_signs abstract = - let module Abstract = (val abstract : Abstract) in - let module K = struct - type v = Sign_value.t - let key = Sign_value.sign_key - end in - let module Conv = Convert (Abstract.Val) (K) in - let module Sign = Domain_lift.Make (Sign_domain) (Conv) in - let module Dom = Domain_product.Make (Abstract.Val) (Abstract.Dom) (Sign) in - (module struct - module Val = Abstract.Val - module Loc = Abstract.Loc - module Dom = Dom - end : Abstract) - -(* -------------------------------------------------------------------------- *) -(* Numerors Domain *) -(* -------------------------------------------------------------------------- *) - -let add_errors abstract = - let module Abstract = (val abstract : Abstract) in - let module K = struct - type v = Numerors_domain.value - let key = Numerors_domain.value_key - end in - let module Conv = Convert (Abstract.Val) (K) in - let module Numerors = (val Numerors_domain.numerors_domain ()) in - let module Errors = Domain_lift.Make (Numerors) (Conv) in - let module Dom = Domain_product.Make (Abstract.Val) (Abstract.Dom) (Errors) in - (module struct - module Val = Abstract.Val - module Loc = Abstract.Loc - module Dom = Dom - end : Abstract) + | Some ival -> + try + let ival' = Cvalue.V.project_ival cvalue in + (match ival' with + | Ival.Float _ -> raise Cvalue.V.Not_based_on_null + | _ -> ()); + let reduced_ival = Ival.narrow ival ival' in + let cvalue = Cvalue.V.inject_ival reduced_ival in + cvalue, Some reduced_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 -(* -------------------------------------------------------------------------- *) -(* Traces *) -(* -------------------------------------------------------------------------- *) + 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 +end -let add_traces = - add_standard_domain (module Traces_domain.D) +(* --- Final hook ----------------------------------------------------------- *) -(* -------------------------------------------------------------------------- *) -(* Printer *) -(* -------------------------------------------------------------------------- *) +let final_hooks = ref [] -let add_printer = - add_standard_domain (module Printer_domain) +let register_hook f = + final_hooks := f :: !final_hooks -(* -------------------------------------------------------------------------- *) -(* Build Abstractions *) -(* -------------------------------------------------------------------------- *) +let apply_final_hooks abstractions = + List.fold_left (fun acc f -> f acc) abstractions !final_hooks -let build_abstractions config = - let value = build_value config in - let module V = (val value : V) in - let abstractions = - match V.structure with - | Structure.Key_Value.Leaf key - when Structure.Key_Value.equal key Main_values.cvalue_key -> - default_root_abstraction config - | _ -> build_root_abstraction config value - in - let abstractions = - if config.apron_oct - then add_apron_domain abstractions (module Apron_domain.Octagon) - else abstractions - in - let abstractions = - if config.apron_box - then add_apron_domain abstractions (module Apron_domain.Box) - else abstractions - in - let abstractions = - if config.polka_loose - then add_apron_domain abstractions (module Apron_domain.Polka_Loose) - else abstractions - in - let abstractions = - if config.polka_strict - then add_apron_domain abstractions (module Apron_domain.Polka_Strict) - else abstractions - in - let abstractions = - if config.polka_equalities - then add_apron_domain abstractions (module Apron_domain.Polka_Equalities) - else abstractions - in - let module A = (val abstractions : Abstract) in - let abstractions = - if config.equalities - then add_equalities (module A) - else abstractions - in - let abstractions = - if config.symbolic_locs - then add_symbolic_locs abstractions - else abstractions - in - let abstractions = - if config.bitwise - then add_offsm abstractions - else abstractions - in - let abstractions = - if config.gauges - then add_gauges abstractions - else abstractions - in - let abstractions = - if config.inout - then add_inout abstractions - else abstractions - in - let abstractions = - if config.signs - then add_signs abstractions - else abstractions - in - let abstractions = - if config.numerors - then add_errors abstractions - else abstractions - in - let abstractions = - if config.printer - then add_printer abstractions - else abstractions - in - let abstractions = - if config.traces - then add_traces abstractions - else abstractions - in - let abstractions = add_dynamic_abstractions abstractions in - abstractions +(* --- 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 Dom = struct + include Acc.Dom + include Structure.Open (Abstract.Domain) (Acc.Dom) -(* Add the reduce function to the value module. *) -module Reduce (Value : Abstract_value.External) = struct + let get_cvalue = match get Cvalue_domain.State.key with + | None -> None + | Some get -> Some (fun s -> fst (get s)) - include Value + let get_cvalue_or_top = match get Cvalue_domain.State.key with + | None -> fun _ -> Cvalue.Model.top + | Some get -> fun s -> fst (get s) - (* 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 = - match Value.get Main_values.interval_key, Value.get Main_values.cvalue_key with - | Some get_interval, Some get_cvalue -> - begin - let set_cvalue = Value.set Main_values.cvalue_key in - let set_interval = Value.set Main_values.interval_key in - fun t -> - match get_interval t with - | None -> begin - let cvalue = get_cvalue t in - try - let ival = Cvalue.V.project_ival cvalue in - set_interval (Some ival) t - with Cvalue.V.Not_based_on_null -> t - end - | Some ival -> - let cvalue = get_cvalue t in - try - let ival' = Cvalue.V.project_ival cvalue in - (match ival' with - | Ival.Float _ -> raise Cvalue.V.Not_based_on_null - | _ -> ()); - let reduced_ival = Ival.narrow ival ival' in - let cvalue = Cvalue.V.inject_ival reduced_ival in - set_interval (Some reduced_ival) (set_cvalue cvalue t) - with Cvalue.V.Not_based_on_null -> t - end - | _, _ -> fun x -> x - - let reduce_error = Numerors_domain.reduce_error (module Value) - - let reduce t = reduce_apron_itv (reduce_error t) + let get_cvalue_or_bottom = function + | `Bottom -> Cvalue.Model.bottom + | `Value state -> get_cvalue_or_top state + end end -let open_abstractions abstraction = - let module Abstract = (val abstraction : Abstract) in - let module Val = Reduce (Abstract.Val) in - let module Loc = struct - include Abstract.Loc - include Structure.Open - (Structure.Key_Location) - (struct include Abstract.Loc type t = location end) - end in - let module Domain = struct - include Abstract.Dom - include Structure.Open (Structure.Key_Domain) (Abstract.Dom) - end in +module CVal = Leaf_Value (Main_values.CVal) + +let unit_acc (module Value: Abstract.Value.External) = + let loc : (module internal_loc 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 = Val - module Loc = Loc - module Dom = Domain - end : S) + module Val = Value + module Loc = (val loc) + module Dom = Unit_domain.Make (Val) (Loc) + end : Acc) + +let build_abstractions config = + 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 acc = unit_acc value in + build_domain config acc +let configure = Config.configure let make config = let abstractions = build_abstractions config in - open_abstractions abstractions - - -(* -------------------------------------------------------------------------- *) -(* Default and Legacy Abstractions *) -(* -------------------------------------------------------------------------- *) - -module Legacy = (val make legacy_config) -module Default = (val make default_config) - - + let abstractions = (module Open (val abstractions): S) in + apply_final_hooks abstractions -(* -Local Variables: -compile-command: "make -C ../../../.." -End: -*) +module Default = (val make Config.default) +module Legacy = (val make Config.legacy) diff --git a/src/plugins/value/engine/abstractions.mli b/src/plugins/value/engine/abstractions.mli index 996f0aaa0392ad6ab229d4cd1f1429419530bd06..4c2909dbb757e52966e0dab66ec42e86473b87b2 100644 --- a/src/plugins/value/engine/abstractions.mli +++ b/src/plugins/value/engine/abstractions.mli @@ -20,55 +20,90 @@ (* *) (**************************************************************************) -(** Constructions of the abstractions used by Eva. *) - -(** Configuration of the abstract domain. *) -type config = { - cvalue : bool; - equalities : bool; - symbolic_locs : bool; - bitwise : bool; - gauges: bool; - apron_oct : bool; - apron_box : bool; - polka_loose : bool; - polka_strict : bool; - polka_equalities : bool; - inout: bool; - signs: bool; - printer: bool; - numerors: bool; - traces: bool; -} - -(** Default configuration of Eva. *) -val default_config : config - -(** Legacy configuration of Eva, with only the cvalue domain enabled. - May be the default config as well. *) -val legacy_config : config - -(** Build a configuration according to the analysis parameters. *) -val configure : unit -> config +(** Registration and building of the analysis abstractions. *) +(** {2 Registration of abstractions.} *) +(** Dynamic registration of the abstractions to be used in an Eva analysis: + - value abstractions, detailled in the {Abstract_value} signature; + - location abstractions, detailled in the {Abstract_location} signature; + - state abstractions, or abstract domains, detailled in {Abstract_domain}. +*) + +(** Module types of value abstractions: either a single leaf module, or + a compound of several modules described by a structure. *) +type 'v value = + | Single of (module Abstract_value.Leaf with type t = 'v) + | Struct of 'v Abstract.Value.structure + +(** For the moment, all domains must use [precise_loc] as their location + abstraction, and no new location abstraction can be registered for an + analysis. + If you need to build a new location abstraction, please contact us. *) +type precise_loc = Precise_locs.precise_location + +(** Module type of a leaf domain over precise_loc abstraction. *) +module type leaf_domain = Abstract_domain.Leaf with type location = precise_loc + +(** Module type of a functor building a leaf domain from a value abstraction. + The resulting domain must use the input value as value abstraction. *) +module type domain_functor = functor + (Value: Abstract.Value.External) -> (leaf_domain with type value = Value.t) + +(** Type of domain to be registered: either a leaf module with ['v] as value + abstraction, or a functor building a domain from any value abstraction. *) +type 'v domain = + | Domain: (module leaf_domain with type value = 'v) -> 'v domain + | Functor: (module domain_functor) -> _ domain + +(** Abstraction to be registered. The name of each abstraction must be unique. + The priority can be any integer; domains with higher priority are always + processed first. The domains currently provided by Eva have priority ranging + between 1 and 19, so a priority of 0 (respectively 20) ensures that a new + domain is processed after (respectively before) the classic Eva domains. *) +type 'v abstraction = + { name: string; (** Name of the abstraction. Must be unique. *) + priority: int; (** Domains with higher priority are processed first. *) + values: 'v value; (** The value abstraction. *) + domain: 'v domain; (** The domain over the value abstraction. *) + } + +(** Register an abstraction. The abstraction is used in an Eva analysis only if + [enable ()] returns true at the start of the analysis. *) +val register: enable:(unit -> bool) -> 'v abstraction -> unit + +(** Register a dynamic abstraction: the abstraction is built by applying + [make (configure ())] at the start of each analysis. *) +val dynamic_register: + configure:(unit -> 'a option) -> make:('a -> 'v abstraction) -> unit + +(** Value reduced product between two value abstractions, identified by their + keys. *) +type ('a, 'b) value_reduced_product = + 'a Abstract.Value.key * 'b Abstract.Value.key * ('a -> 'b -> 'a * 'b) + +(** Register a reduction function for a value reduced product. *) +val register_value_reduction: ('a, 'b) value_reduced_product -> unit + + +(** {2 Types used in the engine.} *) + +(** The external signature of value abstractions, plus the reduction function + of the reduced product. *) module type Value = sig - include Abstract_value.External + include Abstract.Value.External val reduce : t -> t end -(** Types of the abstractions of the analysis: value, location and state - abstractions.*) +(** The three abstractions used in an Eva analysis. *) module type S = sig module Val : Value - module Loc : Abstract_location.External with type value = Val.t - module Dom : Abstract_domain.External with type value = Val.t + 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 gathering: - - the analysis abstractions: value, location and state abstractions; - - the evaluation functions for these abstractions. *) +(** The three abstractions plus an evaluation engine for these abstractions. *) module type Eva = sig include S module Eval: Evaluation.S with type state = Dom.t @@ -77,26 +112,45 @@ module type Eva = sig and type origin = Dom.origin end -(** Type of abstractions that use the builtin types for values and locations *) -module type Standard_abstraction = Abstract_domain.Internal - with type value = Cvalue.V.t - and type location = Precise_locs.precise_location +(** Register a hook modifying the three abstractions after their building by + the engine, before the start of each analysis. *) +val register_hook: ((module S) -> (module S)) -> unit -val register_dynamic_abstraction: (module Standard_abstraction) -> unit +(** {2 Configuration of an analysis.} *) -(** Builds the abstractions according to a configuration. *) -val make : config -> (module S) +(** Configuration defining the abstractions to be used in an analysis. *) +module Config : sig + (** Flag for an abstraction. *) + type flag = Flag: 'v abstraction -> flag + (** A configuration is a set of flags, i.e. a set of enabled abstractions. *) + include Set.S with type elt = flag -(** Two abstractions are instantiated at compile time: default and legacy - (which may be the same). *) + (** Flags for the standard domains currently provided in Eva. *) -module Legacy : S -module Default : S + val cvalue: flag + val equality: flag + val symbolic_locations: flag + val gauges: flag + val bitwise: flag + val inout: flag + val sign: flag + val traces: flag + val printer: flag + val default: t (** The default configuration of Eva. *) + val legacy: t (** The configuration corresponding to the old "Value" analysis, + with only the cvalue domain enabled. *) +end -(* -Local Variables: -compile-command: "make -C ../../../.." -End: -*) +(** Creates the configuration according to the analysis parameters. *) +val configure: unit -> Config.t + +(** Builds the abstractions according to a configuration. *) +val make: Config.t -> (module S) + +(** Two abstractions are instantiated at compile time for the default and legacy + configurations (which may be the same). *) + +module Legacy : S +module Default : S diff --git a/src/plugins/value/engine/analysis.ml b/src/plugins/value/engine/analysis.ml index fd3cf68003bf90f49e026ed3028488d18cf19c72..ee1b5680eeac44e2ad88489209edf6dbbb7fceb6 100644 --- a/src/plugins/value/engine/analysis.ml +++ b/src/plugins/value/engine/analysis.ml @@ -102,7 +102,7 @@ module Legacy = Make (Abstractions.Legacy) module Default = (val - (if Abstractions.default_config = Abstractions.legacy_config + (if Abstractions.Config.(equal default legacy) then (module Legacy) else (module Make (Abstractions.Default))) : Analyzer) @@ -112,7 +112,7 @@ module Default = the parameters of Eva regarding the abstractions used in the analysis) and the current Analyzer module. *) let ref_analyzer = - ref (Abstractions.default_config, (module Default : Analyzer)) + ref (Abstractions.Config.default, (module Default : Analyzer)) (* Returns the current Analyzer module. *) let current_analyzer () = (module (val (snd !ref_analyzer)): S) @@ -133,14 +133,14 @@ let set_current_analyzer config (analyzer: (module Analyzer)) = let cvalue_initial_state () = let module A = (val snd !ref_analyzer) in let _, lib_entry = Globals.entry_point () in - Cvalue_domain.extract A.Dom.get (A.initial_state ~lib_entry) + A.Dom.get_cvalue_or_bottom (A.initial_state ~lib_entry) (* Builds the Analyzer module corresponding to a given configuration, and sets it as the current analyzer. *) let make_analyzer config = let analyzer = - if config = Abstractions.legacy_config then (module Legacy: Analyzer) - else if config = Abstractions.default_config then (module Default) + if Abstractions.Config.(equal config legacy) then (module Legacy: Analyzer) + else if Abstractions.Config.(equal config default) then (module Default) else let module Abstract = (val Abstractions.make config) in let module Analyzer = Make (Abstract) in @@ -153,7 +153,7 @@ let reset_analyzer () = let config = Abstractions.configure () in (* If the configuration has not changed, do not reset the Analyzer but uses the reference instead. *) - if config <> fst !ref_analyzer + if not (Abstractions.Config.equal config (fst !ref_analyzer)) then make_analyzer config (* Builds the analyzer if needed, and run the analysis. *) diff --git a/src/plugins/value/engine/compute_functions.ml b/src/plugins/value/engine/compute_functions.ml index d265352833e4dbbf7b2d88c7ed8483849670c57d..21a9876322a1e7dfe27fdc0a8c9d0dc8803ce778 100644 --- a/src/plugins/value/engine/compute_functions.ml +++ b/src/plugins/value/engine/compute_functions.ml @@ -148,18 +148,13 @@ module Make (Abstract: Abstractions.Eva) = struct let initial_state = Init.initial_state - let get_cvalue = - match Abstract.Dom.get Cvalue_domain.key with - | None -> fun _ -> Cvalue.Model.top - | Some get -> fun state -> get state - let get_cval = - match Abstract.Val.get Main_values.cvalue_key with + match Abstract.Val.get Main_values.CVal.key with | None -> fun _ -> assert false | Some get -> fun value -> get value let get_ploc = - match Abstract.Loc.get Main_locations.ploc_key with + match Abstract.Loc.get Main_locations.PLoc.key with | None -> fun _ -> assert false | Some get -> fun location -> get location @@ -191,7 +186,7 @@ module Make (Abstract: Abstractions.Eva) = struct then `Spec (Annotations.funspec kf) else `Def def in - let cvalue_state = get_cvalue state in + let cvalue_state = Abstract.Dom.get_cvalue_or_top state in let resulting_states, cacheable = match use_spec with | `Spec spec -> Db.Value.Call_Type_Value_Callbacks.apply @@ -237,9 +232,9 @@ module Make (Abstract: Abstractions.Eva) = struct in call_result | Some (states, i) -> - let stack_with_call = Value_util.call_stack () in - Db.Value.Call_Type_Value_Callbacks.apply - (`Memexec, get_cvalue init_state, stack_with_call); + let stack = Value_util.call_stack () in + let cvalue = Abstract.Dom.get_cvalue_or_top init_state in + Db.Value.Call_Type_Value_Callbacks.apply (`Memexec, cvalue, stack); (* Evaluate the preconditions of kf, to update the statuses at this call. *) let spec = Annotations.funspec call.kf in @@ -300,7 +295,7 @@ module Make (Abstract: Abstractions.Eva) = struct in Locations.Location_Bytes.do_track_garbled_mix true; let final_state = states >>- join_states in - let cvalue_state = get_cvalue state in + let cvalue_state = Abstract.Dom.get_cvalue_or_top state in match final_state with | `Bottom -> let cs = Value_util.call_stack () in @@ -312,17 +307,16 @@ module Make (Abstract: Abstractions.Eva) = struct let cvalue_states, cacheable = Builtins.apply_builtin builtin cvalue_call cvalue_state in - let insert (cvalue_state, clobbered_set) = - Abstract.Dom.set Locals_scoping.key clobbered_set - (Abstract.Dom.set Cvalue_domain.key cvalue_state final_state) + let insert cvalue_state = + Abstract.Dom.set Cvalue_domain.State.key cvalue_state final_state in let states = Bottom.bot_of_list (List.map insert cvalue_states) in Transfer.{states; cacheable; builtin=true} let compute_call = - if Abstract.Dom.mem Cvalue_domain.key - && Abstract.Val.mem Main_values.cvalue_key - && Abstract.Loc.mem Main_locations.ploc_key + if Abstract.Dom.mem Cvalue_domain.State.key + && Abstract.Val.mem Main_values.CVal.key + && Abstract.Loc.mem Main_locations.PLoc.key then compute_call_or_builtin else compute_and_cache_call @@ -330,7 +324,7 @@ module Make (Abstract: Abstractions.Eva) = struct let store_initial_state kf init_state = Abstract.Dom.Store.register_initial_state (Value_util.call_stack ()) init_state; - let cvalue_state = get_cvalue init_state in + let cvalue_state = Abstract.Dom.get_cvalue_or_top init_state in Db.Value.Call_Value_Callbacks.apply (cvalue_state, [kf, Kglobal]) let compute kf init_state = diff --git a/src/plugins/value/engine/evaluation.ml b/src/plugins/value/engine/evaluation.ml index cc4018b105ace85d2ef41e338aede20e702b64bf..b56d00620330f489f0e440f296aa0e575f5b6465 100644 --- a/src/plugins/value/engine/evaluation.ml +++ b/src/plugins/value/engine/evaluation.ml @@ -263,7 +263,7 @@ let indeterminate_copy lval result alarms = module type Value = sig - include Abstract_value.External + include Abstract.Value.External val reduce : t -> t end diff --git a/src/plugins/value/engine/evaluation.mli b/src/plugins/value/engine/evaluation.mli index ad8886669f22c25f17b0a08d404ba0c81efd8cec..f7febc17e4242c9d2b6f01189995ec86afcdfecc 100644 --- a/src/plugins/value/engine/evaluation.mli +++ b/src/plugins/value/engine/evaluation.mli @@ -104,7 +104,7 @@ module type S = sig end module type Value = sig - include Abstract_value.External + include Abstract.Value.External (** Inter-reduction of values. Useful when the value module is a reduced product of several abstraction. diff --git a/src/plugins/value/engine/initialization.ml b/src/plugins/value/engine/initialization.ml index 317446467c2dcd3b4e657f30019dc3407b098146..fd124a687b6a27f5c823130697fcad9ca2042a7a 100644 --- a/src/plugins/value/engine/initialization.ml +++ b/src/plugins/value/engine/initialization.ml @@ -80,7 +80,7 @@ let (>>>) t f = match t with let counter = ref 0 module Make - (Domain: Abstract_domain.External) + (Domain: Abstract.Domain.External) (Eva: Evaluation.S with type state = Domain.state and type loc = Domain.location) (Transfer: Transfer_stmt.S with type state = Domain.t) @@ -270,10 +270,9 @@ module Make (* Use the values supplied in [actuals] for the formals of [kf], and bind them in [state] *) let add_supplied_main_formals kf actuals state = - match Domain.get Cvalue_domain.key with - | None -> - Value_parameters.abort "Function Db.Value.fun_set_args cannot be used \ - without the Cvalue domain" + match Domain.get_cvalue with + | None -> Value_parameters.abort "Function Db.Value.fun_set_args cannot be \ + used without the Cvalue domain" | Some get_cvalue -> let formals = Kernel_function.get_formals kf in if (List.length formals) <> List.length actuals then @@ -286,8 +285,8 @@ module Make let cvalue_state = List.fold_left2 add_actual cvalue_state actuals formals in - let set_domain = Domain.set Cvalue_domain.key in - set_domain cvalue_state state + let set_domain = Domain.set Cvalue_domain.State.key in + set_domain (cvalue_state, Locals_scoping.bottom ()) state let add_main_formals kf state = match Db.Value.fun_get_args () with @@ -354,7 +353,9 @@ module Make let supplied_state () = let cvalue_state = Db.Value.globals_state () in if Cvalue.Model.is_reachable cvalue_state - then `Value (Domain.set Cvalue_domain.key cvalue_state Domain.top) + then + let cvalue_state = cvalue_state, Locals_scoping.bottom () in + `Value (Domain.set Cvalue_domain.State.key cvalue_state Domain.top) else `Bottom let initial_state ~lib_entry = @@ -363,7 +364,7 @@ module Make else global_state ~lib_entry let print_initial_cvalue_state state = - let cvalue_state = Cvalue_domain.extract Domain.get state in + let cvalue_state = Domain.get_cvalue_or_bottom state in (* Do not show variables from the frama-c libc specifications. *) let print_base base = try diff --git a/src/plugins/value/engine/initialization.mli b/src/plugins/value/engine/initialization.mli index d3bf03c164d12c1a524f8efffead3446eb2b17eb..f87a4799a8dabf85382536a3faf4beb8eb9deab9 100644 --- a/src/plugins/value/engine/initialization.mli +++ b/src/plugins/value/engine/initialization.mli @@ -44,7 +44,7 @@ module type S = sig end module Make - (Domain: Abstract_domain.External) + (Domain: Abstract.Domain.External) (Eva: Evaluation.S with type state = Domain.state and type loc = Domain.location) (Transfer: Transfer_stmt.S with type state = Domain.t) diff --git a/src/plugins/value/engine/iterator.ml b/src/plugins/value/engine/iterator.ml index 541d61dd21f62783f1efeb762824b51b4bb54b27..bae4fbcc7b35ec5ec246816cd8ab55f9f6bcfe47 100644 --- a/src/plugins/value/engine/iterator.ml +++ b/src/plugins/value/engine/iterator.ml @@ -433,9 +433,7 @@ module Make_Dataflow edge_info.fireable <- true; flow - let get_cvalue = Domain.get Cvalue_domain.key - let gather_cvalues states = - match get_cvalue with + let gather_cvalues states = match Domain.get_cvalue with | Some get -> List.map get states | None -> [] @@ -633,9 +631,6 @@ module Make_Dataflow G.iter_edges_e fill graph; Db.Value.merge_conditions table - let extract_cvalue (state : state) : 'a = - Cvalue_domain.extract Domain.get (`Value state) - let is_instr s = match s.skind with Instr _ -> true | _ -> false let states_after_stmt states_before states_after = @@ -676,7 +671,7 @@ module Make_Dataflow then VertexTable.memo merged_states v get_smashed_store else `Bottom and lift_to_cvalues table = - StmtTable.map (fun _ s -> extract_cvalue s) (Lazy.force table) + StmtTable.map (fun _ s -> Domain.get_cvalue_or_top s) (Lazy.force table) in let merged_pre_states = lazy (StmtTable.map' (fun s (v,_) -> get_merged_states ~all:true s v) automaton.stmt_table) @@ -691,7 +686,7 @@ module Make_Dataflow (StmtTable.map (fun _stmt (v,_) -> let store = get_vertex_store v in let states = Partition.expanded store in - List.map (fun x -> extract_cvalue x) states) + List.map (fun x -> Domain.get_cvalue_or_top x) states) automaton.stmt_table) in let merged_pre_cvalues = lazy (lift_to_cvalues merged_pre_states) diff --git a/src/plugins/value/engine/partition.ml b/src/plugins/value/engine/partition.ml index 68686f72d14cc2cfa28af182e0714db28e980b5b..644e3bf20b5a617f34df40a686b12dadabab3bf4 100644 --- a/src/plugins/value/engine/partition.ml +++ b/src/plugins/value/engine/partition.ml @@ -245,7 +245,7 @@ struct all states" in (* Get the cvalue *) - let cvalue = match Abstract.Val.get Main_values.cvalue_key with + let cvalue = match Abstract.Val.get Main_values.CVal.key with | Some get_cvalue -> get_cvalue value | None -> fail ~exp "partitioning is disabled when the CValue domain is \ not active" @@ -325,7 +325,7 @@ struct (* --- Applying partitioning actions onto flows --------------------------- *) - let stamp_by_value = match Abstract.Val.get Main_values.cvalue_key with + let stamp_by_value = match Abstract.Val.get Main_values.CVal.key with | None -> fun _ _ _ -> None | Some get -> fun expr expected_values state -> let typ = Cil.typeOf expr in diff --git a/src/plugins/value/engine/partitioning_index.ml b/src/plugins/value/engine/partitioning_index.ml index 08a2f449cf02a90603131b2b7dca16623c10df5e..af4202973238a17d341109ddadd4f1ede3fe9319 100644 --- a/src/plugins/value/engine/partitioning_index.ml +++ b/src/plugins/value/engine/partitioning_index.ml @@ -23,7 +23,8 @@ module type Domain = sig include Abstract_domain.Lattice include Datatype.S_with_collections with type t = state - include Abstract_domain.Interface with type t := state + include Abstract.Interface with type t := state + and type 'a key := 'a Abstract_domain.key end (** Partition of the abstract states, computed for each node by the @@ -45,12 +46,12 @@ module Make (* Optimizations relying on specific features of the cvalue domain. *) - let distinct_subpart = match Domain.get Cvalue_domain.key with + let distinct_subpart = match Domain.get Cvalue_domain.State.key with | None -> fun _ _ -> None | Some get -> fun s1 s2 -> Cvalue_domain.distinct_subpart (get s1) (get s2) - let find_subpart = match Domain.get Cvalue_domain.key with + let find_subpart = match Domain.get Cvalue_domain.State.key with | None -> fun _ _ -> None | Some get -> fun state prefix -> Cvalue_domain.find_subpart (get state) prefix diff --git a/src/plugins/value/engine/partitioning_index.mli b/src/plugins/value/engine/partitioning_index.mli index b4488a2eef755c6056994295834de7d54afba023..9a72e4b44bb7cde362196aebea23713899381e18 100644 --- a/src/plugins/value/engine/partitioning_index.mli +++ b/src/plugins/value/engine/partitioning_index.mli @@ -33,7 +33,8 @@ module type Domain = sig include Abstract_domain.Lattice include Datatype.S_with_collections with type t = state - include Abstract_domain.Interface with type t := state + include Abstract.Interface with type t := state + and type 'a key := 'a Abstract_domain.key end module Make (Domain: Domain) : sig diff --git a/src/plugins/value/engine/subdivided_evaluation.ml b/src/plugins/value/engine/subdivided_evaluation.ml index ae1efe494c8c2dd823b6c5a7dd6b428795ecf024..3d0e928ef9f2da8cd8a22afc259eef4c4c6a90e3 100644 --- a/src/plugins/value/engine/subdivided_evaluation.ml +++ b/src/plugins/value/engine/subdivided_evaluation.ml @@ -368,7 +368,7 @@ module type Forward_Evaluation = sig end module Make - (Value : Abstract_value.External) + (Value : Abstract.Value.External) (Loc : Abstract_location.S with type value = Value.t) (Valuation: Valuation with type value = Value.t and type loc = Loc.location) @@ -379,15 +379,15 @@ module Make (* Values are converted to {!Cvalue.V.t}, because those are currently the only values on which we can split. *) - let get_cval = match Value.get Main_values.cvalue_key with + let get_cval = match Value.get Main_values.CVal.key with | Some get -> get | None -> fun _ -> Cvalue.V.top let set_cval = - let set = Value.set Main_values.cvalue_key in + let set = Value.set Main_values.CVal.key in fun cval v -> set cval v - let activated = Value.mem Main_values.cvalue_key + let activated = Value.mem Main_values.CVal.key module Clear = Clear_Valuation (Valuation) diff --git a/src/plugins/value/engine/subdivided_evaluation.mli b/src/plugins/value/engine/subdivided_evaluation.mli index 745624c457517ac366c4f7734bd7960c9bb6d3d7..71d582bb70d8a4e1f6bda7d6d77b88051d08f994 100644 --- a/src/plugins/value/engine/subdivided_evaluation.mli +++ b/src/plugins/value/engine/subdivided_evaluation.mli @@ -36,7 +36,7 @@ module type Forward_Evaluation = sig end module Make - (Value : Abstract_value.External) + (Value : Abstract.Value.External) (Loc: Abstract_location.S with type value = Value.t) (Valuation: Eval.Valuation with type value = Value.t and type loc = Loc.location) diff --git a/src/plugins/value/engine/transfer_specification.ml b/src/plugins/value/engine/transfer_specification.ml index d5438b227de994181748fcdadfd7c43f3a49b05b..e15091974e5c8cdc7de19f10e67d858ec9a6babc 100644 --- a/src/plugins/value/engine/transfer_specification.ml +++ b/src/plugins/value/engine/transfer_specification.ml @@ -227,16 +227,13 @@ module Make (* Extraction of the precise location and of the cvalue domain: needed to evaluate the location of an assigns clause. *) - let get_ploc = match Location.get Main_locations.ploc_key with + let get_ploc = match Location.get Main_locations.PLoc.key with | None -> fun _ -> Main_locations.PLoc.top | Some get -> get - let set_ploc = Location.set Main_locations.ploc_key + let set_ploc = Location.set Main_locations.PLoc.key let set_location loc = set_ploc (Main_locations.PLoc.make loc) - let get_cvalue_state = match Domain.get Cvalue_domain.key with - | None -> fun _ -> Cvalue.Model.top - | Some get -> get - let make_env state = Eval_terms.env_assigns (get_cvalue_state state) + let make_env state = Eval_terms.env_assigns (Domain.get_cvalue_or_top state) let is_result = function | Assigns (term, _) @@ -299,7 +296,7 @@ module Make end in let check_one_state state = - let cvalue_state = get_cvalue_state state in + let cvalue_state = Domain.get_cvalue_or_top state in List.iter (check_one_assign cvalue_state) assigns in States.iter check_one_state states diff --git a/src/plugins/value/engine/transfer_stmt.ml b/src/plugins/value/engine/transfer_stmt.ml index e7be6f8f5827d5e2172721c25c0a7529cc7e321a..514e4ea789c0db62b5c02857c3417d66e9128ee5 100644 --- a/src/plugins/value/engine/transfer_stmt.ml +++ b/src/plugins/value/engine/transfer_stmt.ml @@ -318,7 +318,7 @@ module Make (Abstract: Abstractions.Eva) = struct (* ------------------- Retro propagation on formals ----------------------- *) - let get_precise_location = Location.get Main_locations.ploc_key + let get_precise_location = Location.get Main_locations.PLoc.key (* [is_safe_argument valuation expr] is true iff the expression [expr] could not have been written during the last call. @@ -559,10 +559,6 @@ module Make (Abstract: Abstractions.Eva) = struct (* ----------------- show_each and dump_each directives ------------------- *) - let extract_cvalue = match Domain.get Cvalue_domain.key with - | None -> fun _ -> Cvalue.Model.top - | Some get -> get - (* The product of domains formats the printing of each leaf domains, by checking their log_category and adding their name before the dump. If the domain is not a product, this needs to be done here. *) @@ -609,7 +605,7 @@ module Make (Abstract: Abstractions.Eva) = struct (* For non scalar expressions, prints the offsetmap of the cvalue domain. *) let show_offsm = - match Domain.get Cvalue_domain.key, Location.get Main_locations.ploc_key with + match Domain.get_cvalue, Location.get Main_locations.PLoc.key with | None, _ | _, None -> fun fmt _ _ -> Format.fprintf fmt "%s" (Unicode.top_string ()) | Some get_cvalue, Some get_ploc -> @@ -621,9 +617,7 @@ module Make (Abstract: Abstractions.Eva) = struct let offsm = fst (Eval.lvaluate ~for_writing:false state lval) >>- fun (_, loc, _) -> - let ploc = get_ploc loc - and cvalue_state = get_cvalue state in - Eval_op.offsetmap_of_loc ploc cvalue_state + Eval_op.offsetmap_of_loc (get_ploc loc) (get_cvalue state) in let typ = Cil.typeOf expr in (Bottom.pretty (Eval_op.pretty_offsetmap typ)) fmt offsm @@ -634,7 +628,7 @@ module Make (Abstract: Abstractions.Eva) = struct (* For scalar expressions, prints the cvalue component of their values. *) let show_value = - match Value.get Main_values.cvalue_key with + match Value.get Main_values.CVal.key with | None -> fun fmt _ _ -> Format.fprintf fmt "%s" (Unicode.top_string ()) | Some get_cval -> fun fmt expr state -> @@ -707,7 +701,7 @@ module Make (Abstract: Abstractions.Eva) = struct {Cvalue_transfer.start_call}. *) let apply_cvalue_callback kf ki_call state = let stack_with_call = (kf, ki_call) :: Value_util.call_stack () in - let cvalue_state = extract_cvalue state in + let cvalue_state = Domain.get_cvalue_or_top state in Db.Value.Call_Value_Callbacks.apply (cvalue_state, stack_with_call); Db.Value.merge_initial_state (Value_util.call_stack ()) cvalue_state; let result = diff --git a/src/plugins/value/gui_files/gui_eval.ml b/src/plugins/value/gui_files/gui_eval.ml index 108079350d90481f0a0ec71c200f2a62b0d93443..8239f3974fe81a150ebdeaa53a488ec29935eb31 100644 --- a/src/plugins/value/gui_files/gui_eval.ml +++ b/src/plugins/value/gui_files/gui_eval.ml @@ -143,13 +143,8 @@ module Make (X: Analysis.S) = struct module Analysis = X - let get_cvalue_state = - match X.Dom.get Cvalue_domain.key with - | None -> fun _ -> Cvalue.Model.top - | Some get -> fun state -> get state - let get_precise_loc = - match X.Loc.get Main_locations.ploc_key with + match X.Loc.get Main_locations.PLoc.key with | None -> fun _ -> Precise_locs.loc_top | Some get -> fun loc -> get loc @@ -210,7 +205,7 @@ module Make (X: Analysis.S) = struct let lval_to_offsetmap state lv = let loc, alarms = X.eval_lval_to_loc state lv in let ok = Alarmset.is_empty alarms in - let state = get_cvalue_state state in + let state = X.Dom.get_cvalue_or_top state in let aux loc (acc_res, acc_ok) = let res, ok = match lv with (* catch simplest pattern *) @@ -273,7 +268,7 @@ module Make (X: Analysis.S) = struct } let null_to_offsetmap state (_:unit) = - let state = get_cvalue_state state in + let state = X.Dom.get_cvalue_or_top state in match Cvalue.Model.find_base_or_default Base.null state with | `Bottom -> GO_InvalidLoc, false, false | `Top -> GO_Top, false, false @@ -335,17 +330,17 @@ module Make (X: Analysis.S) = struct let env_here kf here callstack = let pre = pre_kf kf callstack in - let here = get_cvalue_state here in + let here = X.Dom.get_cvalue_or_top here in let c_labels = Eval_annots.c_labels kf callstack in Eval_terms.env_annot ~c_labels ~pre ~here () let env_pre _kf here _callstack = - let here = get_cvalue_state here in + let here = X.Dom.get_cvalue_or_top here in Eval_terms.env_pre_f ~pre:here () let env_post kf post callstack = let pre = pre_kf kf callstack in - let post = get_cvalue_state post in + let post = X.Dom.get_cvalue_or_top post in let result = if !Db.Value.use_spec_instead_of_definition kf then None diff --git a/src/plugins/value/gui_files/gui_types.ml b/src/plugins/value/gui_files/gui_types.ml index 683fa0398606aed22d2fafb21e85f26d2de82070..f4fad0001bcf153f14c432216195984d1da38804 100644 --- a/src/plugins/value/gui_files/gui_types.ml +++ b/src/plugins/value/gui_files/gui_types.ml @@ -167,8 +167,8 @@ module Make (V: Abstractions.Value) = struct | GA_After r1, GA_After r2 -> equal_gui_res r1 r2 | (GA_After _ | GA_NA | GA_Unchanged | GA_Bottom), _ -> false - let get_cvalue = V.get Main_values.cvalue_key - let from_cvalue v = V.set Main_values.cvalue_key v V.top + let get_cvalue = V.get Main_values.CVal.key + let from_cvalue v = V.set Main_values.CVal.key v V.top let var_of_base base acc = try diff --git a/src/plugins/value/register.ml b/src/plugins/value/register.ml index b7198f212195417767e50c26497c272c0026b8c5..f8617e5ad4eb5c0b021ed543a5102af398231f72 100644 --- a/src/plugins/value/register.ml +++ b/src/plugins/value/register.ml @@ -169,9 +169,14 @@ let () = open Eval -module Val = struct +module CVal = struct include Main_values.CVal - include Structure.Open (Structure.Key_Value) (Main_values.CVal) + let structure = Abstract.Value.Leaf (key, (module Main_values.CVal)) +end + +module Val = struct + include CVal + include Structure.Open (Abstract.Value) (CVal) let reduce t = t end @@ -183,6 +188,8 @@ module Eva = module Transfer = Cvalue_domain.State.Transfer (Eva.Valuation) +let inject_cvalue state = state, Locals_scoping.bottom () + let bot_value = function | `Bottom -> Cvalue.V.bottom | `Value v -> v @@ -192,7 +199,7 @@ let bot_state = function | `Value s -> s let update valuation state = - bot_state (Transfer.update valuation state >>-: Cvalue_domain.project) + bot_state (Transfer.update valuation state >>-: fst) let rec eval_deps state e = match e.enode with @@ -231,7 +238,7 @@ let notify_opt with_alarms alarms = Extlib.may (fun mode -> Alarmset.notify mode alarms) with_alarms let eval_expr_with_valuation ?with_alarms deps state expr= - let state = Cvalue_domain.inject state in + let state = inject_cvalue state in let deps = match deps with | None -> None | Some deps -> @@ -251,7 +258,7 @@ let eval_expr_with_valuation ?with_alarms deps state expr= module Eval = struct let eval_expr ?with_alarms state expr = - let state = Cvalue_domain.inject state in + let state = inject_cvalue state in let eval, alarms = Eva.evaluate ~reduction:false state expr in notify_opt with_alarms alarms; bot_value (eval >>-: snd) @@ -273,7 +280,7 @@ module Eval = struct let reduce_by_cond state expr positive = - let state = Cvalue_domain.inject state in + let state = inject_cvalue state in let eval, _alarms = Eva.reduce state expr positive in @@ -284,7 +291,7 @@ module Eval = struct if not (Cvalue.Model.is_reachable state) then state, deps, Precise_locs.loc_bottom, (Cil.typeOfLval lval) else - let state = Cvalue_domain.inject state in + let state = inject_cvalue state in let deps = match deps with | None -> None | Some deps -> @@ -333,7 +340,7 @@ module Eval = struct let resolv_func_vinfo ?with_alarms deps state funcexp = let open Cil_types in - let state = Cvalue_domain.inject state in + let state = inject_cvalue state in let deps = match funcexp.enode with | Lval (Var _, NoOffset) -> deps | Lval (Mem v, _) -> diff --git a/src/plugins/value/utils/abstract.ml b/src/plugins/value/utils/abstract.ml new file mode 100644 index 0000000000000000000000000000000000000000..e5153a5241bcbd0682795eb13ee79fbe48976499 --- /dev/null +++ b/src/plugins/value/utils/abstract.ml @@ -0,0 +1,94 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2019 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +(** External interface of an abstraction, built by {!Structure.Open}. *) +module type Interface = sig + type t + type 'a key + val mem : 'a key -> bool + val get : 'a key -> (t -> 'a) option + val set : 'a key -> 'a -> t -> t +end + +module Value = struct + + module V = struct + type 'a t = (module Abstract_value.S with type t = 'a) + end + + include Structure.Shape (Structure.Key_Value) (V) + + module type Internal = sig + include Abstract_value.S + val structure: t structure + end + + module type External = sig + include Internal + include Structure.External with type t := t + and type 'a key := 'a key + end +end + +module Location = struct + + module L = struct + type 'a t = (module Abstract_location.S with type location = 'a) + end + + include Structure.Shape (Structure.Key_Location) (L) + + module type Internal = sig + include Abstract_location.S + val structure: location structure + end + + module type External = sig + include Internal + include Structure.External with type t := location + and type 'a key := 'a key + end +end + +module Domain = struct + + module D = struct + type 'a t = (module Abstract_domain.Internal with type state = 'a) + end + + include Structure.Shape (Structure.Key_Domain) (D) + + module type Internal = sig + include Abstract_domain.Internal + val structure: t structure + end + + module type External = sig + include Internal + include Structure.External with type t := t + and type 'a key := 'a key + + val get_cvalue: (t -> Cvalue.Model.t) option + val get_cvalue_or_top: t -> Cvalue.Model.t + val get_cvalue_or_bottom: t Bottom.or_bottom -> Cvalue.Model.t + end +end diff --git a/src/plugins/value/utils/abstract.mli b/src/plugins/value/utils/abstract.mli new file mode 100644 index 0000000000000000000000000000000000000000..3e797f8eddba95cddfa69765f3097ac7a3081ffa --- /dev/null +++ b/src/plugins/value/utils/abstract.mli @@ -0,0 +1,118 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2019 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +(** Internal and External signature of abstractions used in the Eva engine. *) + +(** Internal modules contains a [structure] value that describes the internal + structure of the abstraction. This structure is used to automatically + generate efficient accessors from a generic compound abstraction to specific + leaf abstractions. *) + +(** External modules export direct accessors to their leaf components. + When a generic abstraction is a product of several specific abstractions, + they allow interacting with each leaf abstraction identified by a key. + Note that their behavior is undefined if an abstraction contains + several times the same leaf module. *) + +(** External interface of an abstraction, built by {!Structure.Open}. *) +module type Interface = sig + type t + type 'a key + + (** Tests whether a key belongs to the module. *) + val mem : 'a key -> bool + + (** For a key of type [k key]: + - if the values of type [t] contain a subpart of type [k] from a module + identified by the key, then [get key] returns an accessor for it. + - otherwise, [get key] returns None. *) + val get : 'a key -> (t -> 'a) option + + (** For a key of type [k key]: + - if the values of type [t] contain a subpart of type [k] from a module + identified by the key, then [set key v t] returns the value [t] in which + this subpart has been replaced by [v]. + - otherwise, [set key _] is the identity function. *) + val set : 'a key -> 'a -> t -> t +end + +(** Key and structure for abstract values. + See {structure.mli} for more details. *) +module Value : sig + include Structure.Shape + with type 'a key = 'a Structure.Key_Value.key + and type 'a data = (module Abstract_value.S with type t = 'a) + + module type Internal = sig + include Abstract_value.S + val structure: t structure + end + + module type External = sig + include Internal + include Interface with type t := t + and type 'a key := 'a key + end +end + +(** Key and structure for abstract locations. + See {structure.mli} for more details. *) +module Location : sig + include Structure.Shape + with type 'a key = 'a Structure.Key_Location.key + and type 'a data = (module Abstract_location.S with type location = 'a) + + module type Internal = sig + include Abstract_location.S + val structure: location structure + end + + module type External = sig + include Internal + include Interface with type t := location + and type 'a key := 'a key + end +end + +(** Key and structure for abstract domains. + See {structure.mli} for more details. *) +module Domain : sig + include Structure.Shape + with type 'a key = 'a Structure.Key_Domain.key + and type 'a data = (module Abstract_domain.Internal with type state = 'a) + + module type Internal = sig + include Abstract_domain.Internal + val structure: t structure + end + + module type External = sig + include Internal + include Interface with type t := t + and type 'a key := 'a key + + (** Special accessors for the main cvalue domain. *) + val get_cvalue: (t -> Cvalue.Model.t) option + val get_cvalue_or_top: t -> Cvalue.Model.t + val get_cvalue_or_bottom: t Bottom.or_bottom -> Cvalue.Model.t + end +end diff --git a/src/plugins/value/utils/structure.ml b/src/plugins/value/utils/structure.ml index 30f4b3c38637a85fc888f4e7541ed9cf7b89f51d..c6dd04ab1c1280da7ee2927723be8bf6493c7f85 100644 --- a/src/plugins/value/utils/structure.ml +++ b/src/plugins/value/utils/structure.ml @@ -24,32 +24,22 @@ type (_,_) eq = Eq : ('a,'a) eq module type Key = sig - type 'a k - - val create_key: string -> 'a k - val eq_type : 'a k -> 'b k -> ('a, 'b) eq option + type 'a key - val print: 'a k Pretty_utils.formatter - val compare: 'a k -> 'b k -> int - val equal: 'a k -> 'b k -> bool - val hash : 'a k -> int - val tag: 'a k -> int -end + val create_key: string -> 'a key + val eq_type : 'a key -> 'b key -> ('a, 'b) eq option -module type Shape = sig - include Key - - type 'a structure = - | Void : 'a structure - | Leaf : 'a k -> 'a structure - | Node : 'a structure * 'b structure -> ('a * 'b) structure + val print: 'a key Pretty_utils.formatter + val compare: 'a key -> 'b key -> int + val equal: 'a key -> 'b key -> bool + val hash : 'a key -> int + val tag: 'a key -> int end - module Make (X : sig end) = struct - type 'a k = { tag: int; - name: string } + type 'a key = { tag: int; + name: string } let c = ref (-1) let id () = incr c; !c @@ -57,7 +47,7 @@ module Make (X : sig end) = struct let create_key name = { tag = id (); name } let equal x y = x.tag = y.tag - let eq_type : type a b. a k -> b k -> (a,b) eq option = fun a b -> + let eq_type : type a b. a key -> b key -> (a,b) eq option = fun a b -> if equal a b then Some ((Obj.magic (Eq : (a,a) eq)) : (a,b) eq) else None @@ -67,17 +57,46 @@ module Make (X : sig end) = struct let tag x = x.tag let print fmt x = Format.pp_print_string fmt x.name - - type 'a structure = - | Void : 'a structure - | Leaf : 'a k -> 'a structure - | Node : 'a structure * 'b structure -> ('a * 'b) structure end module Key_Value = Make (struct end) module Key_Location = Make (struct end) module Key_Domain = Make (struct end) +module type Shape = sig + include Key + type 'a data + + type 'a structure = + | Unit : unit structure + | Leaf : 'a key * 'a data -> 'a structure + | Node : 'a structure * 'b structure -> ('a * 'b) structure + + val eq_structure: 'a structure -> 'b structure -> ('a, 'b) eq option +end + +module Shape (Key: Key) (Data: sig type 'a t end) = struct + include Key + type 'a data = 'a Data.t + + type 'a structure = + | Unit : unit structure + | Leaf : 'a key * 'a data -> 'a structure + | Node : 'a structure * 'b structure -> ('a * 'b) structure + + let rec eq_structure : type a b. a structure -> b structure -> (a, b) eq option + = fun a b -> + match a, b with + | Leaf (key1, _), Leaf (key2, _) -> Key.eq_type key1 key2 + | Node (l1, r1), Node (l2, r2) -> + begin + match eq_structure l1 l2, eq_structure r1 r2 with + | Some Eq, Some Eq -> Some Eq + | _, _ -> None + end + | Unit, Unit -> Some Eq + | _, _ -> None +end module type Internal = sig type t @@ -93,7 +112,6 @@ module type External = sig val set : 'a key -> 'a -> t -> t end - module Open (Shape : Shape) (M : sig type t val structure : t Shape.structure end) @@ -110,15 +128,15 @@ module Open open Shape - let rec mem : type a. 'v Shape.k -> a structure -> bool = fun key -> function - | Void -> false - | Leaf k -> Shape.equal key k + let rec mem : type a. 'v Shape.key -> a structure -> bool = fun key -> function + | Unit -> false + | Leaf (k, _) -> Shape.equal key k | Node (left, right) -> mem key left || mem key right let mem key = mem key M.structure - type ('a, 'b) get = 'b Shape.k * ('a -> 'b) + type ('a, 'b) get = 'b Shape.key * ('a -> 'b) type 'a getter = Get : ('a, 'b) get -> 'a getter @@ -130,15 +148,15 @@ module Open let lift_get f (Get (key, get)) = Get (key, fun t -> get (f t)) let rec compute_getters : type a. a structure -> (a getter) KMap.t = function - | Void -> KMap.empty - | Leaf key -> KMap.singleton key (Get (key, fun (t : a) -> t)) + | Unit -> KMap.empty + | Leaf (key, _) -> KMap.singleton key (Get (key, fun (t : a) -> t)) | Node (left, right) -> let l = compute_getters left and r = compute_getters right in let l = KMap.map (lift_get fst) l and r = KMap.map (lift_get snd) r in KMap.merge merge l r let getters = compute_getters M.structure - let get (type a) (key: a Shape.k) : (M.t -> a) option = + let get (type a) (key: a Shape.key) : (M.t -> a) option = match KMap.find key getters with | None -> None | Some (Get (k, get)) -> match Shape.eq_type key k with @@ -146,15 +164,15 @@ module Open | Some Eq -> Some get - type ('a, 'b) set = 'b Shape.k * ('b -> 'a -> 'a) + type ('a, 'b) set = 'b Shape.key * ('b -> 'a -> 'a) type 'a setter = Set : ('a, 'b) set -> 'a setter let lift_set f (Set (key, set)) = Set (key, fun v b -> f (fun a -> set v a) b) let rec compute_setters : type a. a structure -> (a setter) KMap.t = function - | Void -> KMap.empty - | Leaf key -> KMap.singleton key (Set (key, fun v _t -> v)) + | Unit -> KMap.empty + | Leaf (key, _) -> KMap.singleton key (Set (key, fun v _t -> v)) | Node (left, right) -> let l = compute_setters left and r = compute_setters right in let l = KMap.map (lift_set (fun set (l, r) -> set l, r)) l @@ -162,7 +180,7 @@ module Open KMap.merge merge l r let setters = compute_setters M.structure - let set (type a) (key: a Shape.k) : (a -> M.t -> M.t) = + let set (type a) (key: a Shape.key) : (a -> M.t -> M.t) = match KMap.find key setters with | None -> fun _ t -> t | Some (Set (k, set)) -> match Shape.eq_type key k with diff --git a/src/plugins/value/utils/structure.mli b/src/plugins/value/utils/structure.mli index 9d52978f6930c2a52e2231c8bb41468ce4ca24e6..c04eb8cda7bb222f5b24d2bdfc1a63de1e6214f5 100644 --- a/src/plugins/value/utils/structure.mli +++ b/src/plugins/value/utils/structure.mli @@ -29,43 +29,48 @@ type (_,_) eq = Eq : ('a,'a) eq (** Keys identifying datatypes. *) module type Key = sig - type 'a k + type 'a key - val create_key: string -> 'a k - val eq_type : 'a k -> 'b k -> ('a, 'b) eq option + val create_key: string -> 'a key + val eq_type : 'a key -> 'b key -> ('a, 'b) eq option - val print: 'a k Pretty_utils.formatter - val compare: 'a k -> 'b k -> int - val equal: 'a k -> 'b k -> bool - val hash : 'a k -> int - val tag: 'a k -> int + val print: 'a key Pretty_utils.formatter + val compare: 'a key -> 'b key -> int + val equal: 'a key -> 'b key -> bool + val hash : 'a key -> int + val tag: 'a key -> int end +module Make (X : sig end) : Key + +(** Keys module for the abstract values of Eva. *) +module Key_Value : Key + +(** Keys module for the abstract locations of Eva. *) +module Key_Location : Key + +(** Keys module for the abstract domains of Eva. *) +module Key_Domain : Key + (** A Key module with its structure type. *) module type Shape = sig include Key + type 'a data (** The gadt, based on keys giving the type of each node. Describes the internal structure of a data type. Used internally to automatically generate efficient accessors of its nodes. *) type 'a structure = - | Void : 'a structure - | Leaf : 'a k -> 'a structure + | Unit : unit structure + | Leaf : 'a key * 'a data -> 'a structure | Node : 'a structure * 'b structure -> ('a * 'b) structure -end -module Make (X : sig end) : Shape - - -(** Keys module for the abstract values of Eva. *) -module Key_Value : Shape - -(** Keys module for the abstract locations of Eva. *) -module Key_Location : Shape - -(** Keys module for the abstract domains of Eva. *) -module Key_Domain : Shape + val eq_structure: 'a structure -> 'b structure -> ('a, 'b) eq option +end +module Shape (Key: Key) (Data: sig type 'a t end) : + Shape with type 'a key = 'a Key.key + and type 'a data = 'a Data.t (** Internal view of the tree, with the structure. *) module type Internal = sig @@ -92,4 +97,4 @@ module Open (Shape : Shape) (Data : Internal with type 'a structure := 'a Shape.structure) : External with type t := Data.t - and type 'a key := 'a Shape.k + and type 'a key := 'a Shape.key diff --git a/src/plugins/value/value_parameters.ml b/src/plugins/value/value_parameters.ml index 118115fa8b539e80b95d1a8c038cfc2ce675b067..1de1430a7c101b4894bd7aa0176476f575738ee8 100644 --- a/src/plugins/value/value_parameters.ml +++ b/src/plugins/value/value_parameters.ml @@ -77,6 +77,8 @@ let dkey_incompatible_states = register_category "incompatible-states" let dkey_iterator = register_category "iterator" let dkey_callbacks = register_category "callbacks" let dkey_widening = register_category "widening" +let dkey_experimental = register_category "experimental-ok" + let () = let activate dkey = add_debug_keys dkey in @@ -172,6 +174,18 @@ module BitwiseOffsmDomain = Domain_Parameter let default = false end) +let numerors_available = ref false +let register_numerors () = numerors_available := true + +let numerors_hook _ _ = + if not !numerors_available + then + abort + "The numerors domain has been requested but is not available,@ \ + as Frama-C did not found the MPFR library. The analysis is aborted." + else if not (is_debug_key_enabled dkey_experimental) then + warning "The numerors domain is experimental."; + module NumerorsDomain = Domain_Parameter (struct let option_name = "-eva-numerors-domain" @@ -180,16 +194,28 @@ module NumerorsDomain = Domain_Parameter computations" let default = false end) +let () = NumerorsDomain.add_set_hook numerors_hook let apron_help = "Experimental binding of the numerical domains provided \ by the APRON library: http://apron.cri.ensmp.fr/library \n" +let apron_available = ref false +let register_apron () = apron_available := true + +let apron_hook _ _ = + if not !apron_available + then + abort "an Apron domain is requested but the apron binding is not available." + else if not (is_debug_key_enabled dkey_experimental) then + warning "The Apron domains binding is experimental."; + module ApronOctagon = Domain_Parameter (struct let option_name = "-eva-apron-oct" let help = apron_help ^ "Use the octagon domain of apron." let default = false end) +let () = ApronOctagon.add_set_hook apron_hook module ApronBox = Domain_Parameter (struct @@ -197,6 +223,7 @@ module ApronBox = Domain_Parameter let help = apron_help ^ "Use the box domain of apron." let default = false end) +let () = ApronBox.add_set_hook apron_hook module PolkaLoose = Domain_Parameter (struct @@ -204,6 +231,7 @@ module PolkaLoose = Domain_Parameter let help = apron_help ^ "Use the loose polyhedra domain of apron." let default = false end) +let () = PolkaLoose.add_set_hook apron_hook module PolkaStrict = Domain_Parameter (struct @@ -211,6 +239,7 @@ module PolkaStrict = Domain_Parameter let help = apron_help ^ "Use the strict polyhedra domain of apron." let default = false end) +let () = PolkaStrict.add_set_hook apron_hook module PolkaEqualities = Domain_Parameter (struct @@ -218,6 +247,7 @@ module PolkaEqualities = Domain_Parameter let help = apron_help ^ "Use the linear equalities domain of apron." let default = false end) +let () = PolkaEqualities.add_set_hook apron_hook module InoutDomain = Domain_Parameter (struct diff --git a/src/plugins/value/value_parameters.mli b/src/plugins/value/value_parameters.mli index dc958517ee46ca0c0430e3ee513b75662d9b88c9..3e0fb860496b052159093bf18d4239e97379081a 100644 --- a/src/plugins/value/value_parameters.mli +++ b/src/plugins/value/value_parameters.mli @@ -234,6 +234,11 @@ val dkey_callbacks : category val dkey_widening : category +(** Notifies that the binding to Apron domains is available. *) +val register_apron: unit -> unit + +(** Notifies that the numerors domain is available. *) +val register_numerors: unit -> unit (* Local Variables: diff --git a/src/plugins/value/values/abstract_location.mli b/src/plugins/value/values/abstract_location.mli index 2c7266aa87353cdcf86e012121bc23f026d2d010..6242ecc18d1f1b3df5d183dbccc6b59aeeb41cf2 100644 --- a/src/plugins/value/values/abstract_location.mli +++ b/src/plugins/value/values/abstract_location.mli @@ -119,21 +119,14 @@ module type S = sig typ -> index:value -> remaining:offset -> offset -> (value * offset) or_bottom end -(** Key and structure for locations. See {structure.mli}, - and {domain.mli} where the mechanism is explained in detail.*) +type 'loc key = 'loc Structure.Key_Location.key -type 'a key = 'a Structure.Key_Location.k -type 'a structure = 'a Structure.Key_Location.structure - -module type Internal = sig +(** Signature for a leaf module of abstract locations. *) +module type Leaf = sig include S - val structure : location structure -end -module type External = sig - include S - include Structure.External with type t := location - and type 'a key := 'a key + (** The key identifies the module and the type [t] of abstract locations. *) + val key: location key end (* diff --git a/src/plugins/value/values/abstract_value.mli b/src/plugins/value/values/abstract_value.mli index 28fec80b0e53acad4535b0655b86601a5e0b690d..c6efd63271876b27d54960adc4f32e5697b3d139 100644 --- a/src/plugins/value/values/abstract_value.mli +++ b/src/plugins/value/values/abstract_value.mli @@ -181,21 +181,14 @@ module type S = sig end -(** Key and structure for values. See {structure.mli}, - and {domain.mli} where the mechanism is explained in detail.*) +type 'v key = 'v Structure.Key_Value.key -type 'a key = 'a Structure.Key_Value.k -type 'a structure = 'a Structure.Key_Value.structure - -module type Internal = sig +(** Signature for a leaf module of abstract values. *) +module type Leaf = sig include S - val structure : t structure -end -module type External = sig - include S - include Structure.External with type t := t - and type 'a key := 'a key + (** The key identifies the module and the type [t] of abstract values. *) + val key: t key end diff --git a/src/plugins/value/values/location_lift.ml b/src/plugins/value/values/location_lift.ml index ce5ae27c8641259ef90652d9d36dffffee6ad2bf..f02568133bbbfd282a44abb8b20cf7f70f5e51af 100644 --- a/src/plugins/value/values/location_lift.ml +++ b/src/plugins/value/values/location_lift.ml @@ -32,17 +32,19 @@ module type Conversion = sig end module Make - (Loc: Abstract_location.Internal) + (Loc: Abstract_location.Leaf) (Convert : Conversion with type internal_value := Loc.value) = struct (* Import most of [Loc] *) - include (Loc: Abstract_location.Internal + include (Loc: Abstract_location.S with type value := Loc.value (* we are converting this type *) and type location = Loc.location and type offset = Loc.offset) type value = Convert.extended_value + let structure = Abstract.Location.Leaf (Loc.key, (module Loc)) + (* Now lift the functions that contain {!value} in their type. *) let to_value loc = Convert.extend_val (Loc.to_value loc) diff --git a/src/plugins/value/values/location_lift.mli b/src/plugins/value/values/location_lift.mli index 1eb2d98d38c1da61d05b0891f7e6f88cda650e87..cd5b46cafaf7143981d76060b05f4be48b656f4d 100644 --- a/src/plugins/value/values/location_lift.mli +++ b/src/plugins/value/values/location_lift.mli @@ -30,9 +30,9 @@ module type Conversion = sig end module Make - (Loc: Abstract_location.Internal) + (Loc: Abstract_location.Leaf) (Convert : Conversion with type internal_value := Loc.value) - : Abstract_location.Internal with type location = Loc.location + : Abstract.Location.Internal with type location = Loc.location and type offset = Loc.offset and type value = Convert.extended_value diff --git a/src/plugins/value/values/main_locations.ml b/src/plugins/value/values/main_locations.ml index f98119eab16be0479dd44dbd92e7c66bb668296d..8722ef3517205bc1e9d53b74c754e44cc6a87292 100644 --- a/src/plugins/value/values/main_locations.ml +++ b/src/plugins/value/values/main_locations.ml @@ -22,8 +22,6 @@ open Cil_types -let ploc_key = Structure.Key_Location.create_key "precise_locs" - module PLoc = struct type value = Cvalue.V.t @@ -32,7 +30,7 @@ module PLoc = struct | Precise of Precise_locs.precise_offset | Imprecise of Cvalue.V.t (* when the offset contains addresses *) - let structure = Structure.Key_Location.Leaf ploc_key + let key = Structure.Key_Location.create_key "precise_locs" let equal_loc = Precise_locs.equal_loc let equal_offset o1 o2 = match o1, o2 with diff --git a/src/plugins/value/values/main_locations.mli b/src/plugins/value/values/main_locations.mli index 28d11c16b762f742bdcc3364c4d01de67d6ca0c3..7701838d407cb735e23a76bd8de2a1f74bdb558a 100644 --- a/src/plugins/value/values/main_locations.mli +++ b/src/plugins/value/values/main_locations.mli @@ -25,7 +25,7 @@ (** Abstract locations built over Precise_locs. *) module PLoc : sig - include Abstract_location.Internal + include Abstract_location.Leaf with type value = Cvalue.V.t and type location = Precise_locs.precise_location @@ -33,10 +33,6 @@ module PLoc : sig end -(** Key for precise locs. *) -val ploc_key : PLoc.location Abstract_location.key - - (* Local Variables: compile-command: "make -C ../../../.." diff --git a/src/plugins/value/values/main_values.ml b/src/plugins/value/values/main_values.ml index f5bec06d977060be6fd796cedaea8bfde736f059..83b93bbfb6321503ef84c4d54421936a7e2cd2b1 100644 --- a/src/plugins/value/values/main_values.ml +++ b/src/plugins/value/values/main_values.ml @@ -22,12 +22,10 @@ open Cil_types -let cvalue_key = Structure.Key_Value.create_key "cvalue" - module CVal = struct include Cvalue.V - let structure = Structure.Key_Value.Leaf cvalue_key + let key = Structure.Key_Value.create_key "cvalue" let zero = Cvalue.V.singleton_zero let one = Cvalue.V.singleton_one @@ -135,12 +133,10 @@ module CVal = struct with Abstract_interp.Error_Top -> `Top, true end -let interval_key = Structure.Key_Value.create_key "interval" - module Interval = struct include Datatype.Option (Ival) - let structure = Structure.Key_Value.Leaf interval_key + let key = Structure.Key_Value.create_key "interval" let pretty_typ _ = pretty diff --git a/src/plugins/value/values/main_values.mli b/src/plugins/value/values/main_values.mli index fd148fcfcc5208e58353e0a847249b4d715a3c14..4923f3182ed2e685eaefa4653bae7a840b9b0fb8 100644 --- a/src/plugins/value/values/main_values.mli +++ b/src/plugins/value/values/main_values.mli @@ -23,17 +23,11 @@ (** Main numeric values of Eva. *) (** Abstract values built over Cvalue.V *) -module CVal : Abstract_value.Internal with type t = Cvalue.V.t - -(** Key for cvalues. *) -val cvalue_key : CVal.t Abstract_value.key +module CVal : Abstract_value.Leaf with type t = Cvalue.V.t (** Dummy interval: no forward nor backward propagations. [None] is top. *) -module Interval : Abstract_value.Internal with type t = Ival.t option - -(** Key for intervals. *) -val interval_key : Interval.t Abstract_value.key +module Interval : Abstract_value.Leaf with type t = Ival.t option (* Local Variables: diff --git a/src/plugins/value/values/numerors/numerors_value.ml b/src/plugins/value/values/numerors/numerors_value.ml index 8fa47dc923f6337a7a09483991e497cb2d08da7f..6ef7042aa6964c78ea5a70bfac37a58a5fb76955 100644 --- a/src/plugins/value/values/numerors/numerors_value.ml +++ b/src/plugins/value/values/numerors/numerors_value.ml @@ -116,8 +116,7 @@ end include Datatype.Make(T) let pretty_debug = pretty let pretty_typ _ = pretty -let error_key = Structure.Key_Value.create_key "numerors_values" -let structure = Structure.Key_Value.Leaf error_key +let key = Structure.Key_Value.create_key "numerors_values" (*----------------------------------------------------------------------------- diff --git a/src/plugins/value/values/numerors/numerors_value.mli b/src/plugins/value/values/numerors/numerors_value.mli index d73b689cd75ca60a4fe10a2cb2eaad9bc625d97a..3c87147b3e30abae9d15aa503bf164147ddaf18c 100644 --- a/src/plugins/value/values/numerors/numerors_value.mli +++ b/src/plugins/value/values/numerors/numerors_value.mli @@ -20,15 +20,13 @@ (* *) (**************************************************************************) -include Abstract_value.Internal +include Abstract_value.Leaf val pretty_debug : t Pretty_utils.formatter (** Reduction of an error value according to a floating-point interval. *) val reduce: Fval.t -> t -> t Eval.or_bottom -val error_key : t Structure.Key_Value.k - val set_absolute_to_top : t -> t val set_relative_to_top : t -> t diff --git a/src/plugins/value/values/offsm_value.ml b/src/plugins/value/values/offsm_value.ml index a447493695dcb04a94297946066499e67a8c077c..1465804854fcd34cab00ffe0d572657ea2951c7b 100644 --- a/src/plugins/value/values/offsm_value.ml +++ b/src/plugins/value/values/offsm_value.ml @@ -381,12 +381,10 @@ module Datatype_Offsm_or_top = Datatype.Make_with_collections(struct end) -let offsm_key = Structure.Key_Value.create_key "offsetmap_value" - -module Offsm : Abstract_value.Internal with type t = offsm_or_top = struct +module Offsm : Abstract_value.Leaf with type t = offsm_or_top = struct include Datatype_Offsm_or_top - let structure = Structure.Key_Value.Leaf offsm_key + let key = Structure.Key_Value.create_key "offsetmap_value" let pretty_typ typ fmt = function | Top as o -> pretty fmt o @@ -480,10 +478,14 @@ module Offsm : Abstract_value.Internal with type t = offsm_or_top = struct end -module CvalueOffsm : Abstract_value.Internal with type t = V.t * offsm_or_top +module CvalueOffsm : Abstract.Value.Internal with type t = V.t * offsm_or_top = struct include Value_product.Make (Main_values.CVal) (Offsm) + let structure = + Abstract.Value.(Node (Leaf (Main_values.CVal.key, (module Main_values.CVal)), + Leaf (Offsm.key, (module Offsm)))) + let size typ = Integer.of_int (Cil.bitsSizeOf typ) (* Extract an offsetmap from a pair, by converting the value when needed. *) diff --git a/src/plugins/value/values/offsm_value.mli b/src/plugins/value/values/offsm_value.mli index 1ad67480937996b32bffb54068b50d30ec4ef640..6465583c14eac05255723276ac81be8d94f5cafb 100644 --- a/src/plugins/value/values/offsm_value.mli +++ b/src/plugins/value/values/offsm_value.mli @@ -22,13 +22,10 @@ type offsm_or_top = O of Cvalue.V_Offsetmap.t | Top -val offsm_key : offsm_or_top Structure.Key_Value.k - val cast : old_size: Integer.t -> new_size: Integer.t -> signed: bool -> Cvalue.V_Offsetmap.t -> Cvalue.V_Offsetmap.t +module Offsm : Abstract_value.Leaf with type t = offsm_or_top -module Offsm : Abstract_value.Internal with type t = offsm_or_top - -module CvalueOffsm : Abstract_value.Internal with type t = Cvalue.V.t * offsm_or_top +module CvalueOffsm : Abstract.Value.Internal with type t = Cvalue.V.t * offsm_or_top diff --git a/src/plugins/value/values/sign_value.ml b/src/plugins/value/values/sign_value.ml index 211ce3cd5b2891d14d9a44a6e6f5862aed9eb762..66ebbb989c5bd9fd1fe05f9c2d258e59e66feaff 100644 --- a/src/plugins/value/values/sign_value.ml +++ b/src/plugins/value/values/sign_value.ml @@ -271,5 +271,4 @@ let backward_cast ~src_typ:_ ~dst_typ:_ ~src_val:_ ~dst_val:_ = `Value None (** {2 Misc} *) (* Eva boilerplate, used to retrieve the domain. *) -let sign_key = Structure.Key_Value.create_key "sign_values" -let structure = Structure.Key_Value.Leaf sign_key +let key = Structure.Key_Value.create_key "sign_values" diff --git a/src/plugins/value/values/sign_value.mli b/src/plugins/value/values/sign_value.mli index 14deeda643e120747070f6106980b9acb1d5494f..44b761fb982e26370f6bc2f85c71e0618c85150b 100644 --- a/src/plugins/value/values/sign_value.mli +++ b/src/plugins/value/values/sign_value.mli @@ -22,8 +22,6 @@ (** Sign domain: abstraction of integer numerical values by their signs. *) -include Abstract_value.Internal +include Abstract_value.Leaf val pretty_debug: t Pretty_utils.formatter - -val sign_key : t Structure.Key_Value.k diff --git a/src/plugins/value/values/value_product.ml b/src/plugins/value/values/value_product.ml index 131d47bfa680cd438e8146e4de79bcf1a3b99d29..5a088c5283873e658f87f003c5766d010bf1dda8 100644 --- a/src/plugins/value/values/value_product.ml +++ b/src/plugins/value/values/value_product.ml @@ -23,14 +23,12 @@ open Eval module Make - (Left: Abstract_value.Internal) - (Right: Abstract_value.Internal) + (Left: Abstract_value.S) + (Right: Abstract_value.S) = struct include Datatype.Pair (Left) (Right) - let structure = Structure.Key_Value.Node (Left.structure, Right.structure) - let pretty_typ typ = Pretty_utils.pp_pair ~pre:"@[" ~sep:",@ " ~suf:"@]" (Left.pretty_typ typ) (Right.pretty_typ typ) diff --git a/src/plugins/value/values/value_product.mli b/src/plugins/value/values/value_product.mli index f6369ee2efd75c5241cb13ca4243de875428f610..c24505d85e3f7e748301f1d05570e6df56b137d5 100644 --- a/src/plugins/value/values/value_product.mli +++ b/src/plugins/value/values/value_product.mli @@ -23,9 +23,9 @@ (** Cartesian product of two value abstractions. *) module Make - (Left: Abstract_value.Internal) - (Right: Abstract_value.Internal) - : Abstract_value.Internal with type t = Left.t * Right.t + (Left: Abstract_value.S) + (Right: Abstract_value.S) + : Abstract_value.S with type t = Left.t * Right.t (*