From 9a5a3ec37e903a7f9ebb4c66684a7f4b80ac2410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr> Date: Fri, 23 Aug 2019 18:05:13 +0200 Subject: [PATCH] [Eva] Numerors domain registration. --- Makefile | 19 +-- .../domains/numerors/numerors_domain.ko.ml | 39 ----- ...merors_domain.ok.ml => numerors_domain.ml} | 141 +++++++++--------- .../domains/numerors/numerors_domain.mli | 31 +--- src/plugins/value/value_parameters.ml | 13 ++ src/plugins/value/value_parameters.mli | 3 + 6 files changed, 92 insertions(+), 154 deletions(-) delete mode 100644 src/plugins/value/domains/numerors/numerors_domain.ko.ml rename src/plugins/value/domains/numerors/{numerors_domain.ok.ml => numerors_domain.ml} (57%) diff --git a/Makefile b/Makefile index c475e1a48da..a4ba43c60ea 100644 --- a/Makefile +++ b/Makefile @@ -832,32 +832,18 @@ endif 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 @@ -886,7 +872,6 @@ PLUGIN_CMO:= slevel/split_strategy value_parameters \ 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 \ @@ -909,7 +894,7 @@ PLUGIN_CMO:= slevel/split_strategy value_parameters \ engine/iterator \ engine/initialization \ engine/compute_functions engine/analysis register \ - $(APRON_CMO) + $(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/src/plugins/value/domains/numerors/numerors_domain.ko.ml b/src/plugins/value/domains/numerors/numerors_domain.ko.ml deleted file mode 100644 index eb6bc8b9a4f..00000000000 --- 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 0837c354d0f..338214a370c 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.key - -let ok = true - +(* The numerors values, plus some builtin functions. *) module Numerors_Value = struct include Numerors_value @@ -87,65 +80,7 @@ module Numerors_Value = struct ] end -let add_numerors_value (module Value: Abstract.Value.Internal) = - let module External_Value = Structure.Open (Abstract.Value) (Value) in - let module V = struct - include Value_product.Make (Value) (Numerors_value) - - let structure = - Abstract.Value.(Node (Value.structure, - Leaf (Numerors_value.key, (module Numerors_value)))) - - let forward_cast = match External_Value.get Main_values.CVal.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.key, V.get Main_values.CVal.key with - | Some get_error, Some get_cvalue -> - begin - let set_error = V.set Numerors_value.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) @@ -161,7 +96,71 @@ module Domain = struct | _, _ -> () end -let numerors_domain () = - Value_parameters.warning "The numerors domain is experimental."; - (module Domain: Abstract_domain.Leaf 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"; + 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 c00510fa309..6fcd35b31ee 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.key - -(** 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.Leaf 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/value_parameters.ml b/src/plugins/value/value_parameters.ml index ccd4fa66c36..1de1430a7c1 100644 --- a/src/plugins/value/value_parameters.ml +++ b/src/plugins/value/value_parameters.ml @@ -174,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" @@ -182,6 +194,7 @@ 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" diff --git a/src/plugins/value/value_parameters.mli b/src/plugins/value/value_parameters.mli index 22a72b258e9..3e0fb860496 100644 --- a/src/plugins/value/value_parameters.mli +++ b/src/plugins/value/value_parameters.mli @@ -237,6 +237,9 @@ 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: compile-command: "make -C ../../.." -- GitLab