diff --git a/Makefile b/Makefile index 58008950bb7de262a7fdac8788a8eb18e1dee6d3..344f46c5033ace000ddfe855e674f21575e1f985 100644 --- a/Makefile +++ b/Makefile @@ -856,7 +856,7 @@ endif # - try to keep the legacy Value before Eva PLUGIN_CMO:= partitioning/split_strategy domains/domain_mode value_parameters \ utils/eva_audit utils/value_perf utils/eva_annotations \ - utils/value_util utils/red_statuses \ + utils/eva_dynamic utils/value_util utils/red_statuses \ utils/mark_noresults \ utils/widen_hints_ext utils/widen \ partitioning/split_return \ @@ -910,7 +910,7 @@ PLUGIN_CMO:= partitioning/split_strategy domains/domain_mode value_parameters \ utils/unit_tests PLUGIN_CMI:= values/abstract_value values/abstract_location \ domains/abstract_domain domains/simpler_domains -PLUGIN_DEPENDENCIES:=Callgraph LoopAnalysis RteGen Server +PLUGIN_DEPENDENCIES:=Server # These files are used by the GUI, but do not depend on Lablgtk VALUE_GUI_AUX:=gui_files/gui_types gui_files/gui_eval \ diff --git a/configure.in b/configure.in index 60f6dab2a2ca8ded43f37965ef3c099e0b52e3d8..a4895377d4a3705db3c720e0540419e69fdc1521 100644 --- a/configure.in +++ b/configure.in @@ -857,7 +857,8 @@ check_plugin(eva,src/plugins/value, [support for value analysis],yes) plugin_use(eva,gui) plugin_use(eva,scope) -plugin_require(eva,callgraph) +plugin_use(eva,inout) +plugin_use(eva,callgraph) plugin_require(eva,server) #################### diff --git a/headers/header_spec.txt b/headers/header_spec.txt index 8c8bf1b685894c8f968ab8958fc69db2f027aaec..4e8f0d8ddef50ed5ce934019dc0204bf6c676898 100644 --- a/headers/header_spec.txt +++ b/headers/header_spec.txt @@ -1485,6 +1485,8 @@ src/plugins/value/utils/eva_annotations.ml: CEA_LGPL_OR_PROPRIETARY src/plugins/value/utils/eva_annotations.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/value/utils/eva_audit.ml: CEA_LGPL_OR_PROPRIETARY src/plugins/value/utils/eva_audit.mli: CEA_LGPL_OR_PROPRIETARY +src/plugins/value/utils/eva_dynamic.ml: CEA_LGPL_OR_PROPRIETARY +src/plugins/value/utils/eva_dynamic.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/value/utils/structure.ml: CEA_LGPL_OR_PROPRIETARY src/plugins/value/utils/structure.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/value/utils/summary.ml: CEA_LGPL_OR_PROPRIETARY diff --git a/src/plugins/callgraph/uses.ml b/src/plugins/callgraph/uses.ml index 2befdd59d1ab047dc12cfa9386e53166c8c8f991..728eae5ed726f01dcec646b1bdb66cb421682d6d 100644 --- a/src/plugins/callgraph/uses.ml +++ b/src/plugins/callgraph/uses.ml @@ -73,6 +73,15 @@ let iter_in_rev_order = in fun f -> I.iter (Cg.get ()) f +let _iter_in_rev_order = + Dynamic.register + ~comment:"Iterate over all the functions in the callgraph in reverse order" + ~plugin:Options.name + "iter_in_rev_order" + Datatype.(func (func Kernel_function.ty unit) unit) + ~journalize:false + iter_in_rev_order + let iter_on_aux iter_dir f kf = let cg = Cg.get () in if Cg.G.mem_vertex cg kf then @@ -116,6 +125,16 @@ let accept_base ~with_formals ~with_locals kf v = | true , _, Declaration (_, vd, _, _) -> Base.is_formal_of_prototype v vd) || is_local_or_formal_of_caller v kf +let _accept_base = + Dynamic.register + ~comment:"Returns [true] if the given base is a global, \ + or a formal or local of either [kf] or one of its callers" + ~plugin:Options.name + "accept_base" + Datatype.(func2 Kernel_function.ty Base.ty bool) + ~journalize:false + (fun kf b -> accept_base ~with_formals:true ~with_locals:true kf b) + let nb_calls () = let g = Cg.get () in (* [g] contains bidirectional edges (from caller to callee and diff --git a/src/plugins/rte/register.ml b/src/plugins/rte/register.ml index 4b7e902243355f0e452b7eff9bde9af57d8bc3aa..523f3a797a92b1f8c1a69565d6b40a2f8a758185 100644 --- a/src/plugins/rte/register.ml +++ b/src/plugins/rte/register.ml @@ -147,6 +147,15 @@ let _ignore = ~journalize:false Visit.get_annotations_exp +let _ignore = + let kf = Kernel_function.ty in + Dynamic.register + ~plugin:"RteGen" + "all_statuses" + Datatype.(list (triple string (func2 kf bool unit) (func kf bool))) + ~journalize:false + Generator.all_statuses + let main () = (* reset "rte generated" properties for all functions *) if Options.Enabled.get () then begin diff --git a/src/plugins/scope/datascope.ml b/src/plugins/scope/datascope.ml index d4cab9e063d6590ddcd1586d9fafb89941ba01e1..26d5806673e8aca286bbdc294cd813dc5c2202cd 100644 --- a/src/plugins/scope/datascope.ml +++ b/src/plugins/scope/datascope.ml @@ -28,11 +28,13 @@ open Cil_types let cat_rm_asserts_name = "rm_asserts" let () = Plugin.default_msg_keys [cat_rm_asserts_name] +let name = "scope" + module R = Plugin.Register (struct - let name = "scope" - let shortname = "scope" + let name = name + let shortname = name let help = "data dependencies higher level functions" end) @@ -694,6 +696,15 @@ let () = ("Value.rm_asserts", Datatype.func Datatype.unit Datatype.unit)) Db.Value.rm_asserts rm_asserts +let rm_asserts = + Dynamic.register + ~comment:"Remove redundant alarms. Used by the Eva plugin." + ~plugin:name + "rm_asserts" + Datatype.(func unit unit) + ~journalize:true + rm_asserts + (* 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 80abee069ddbf66e854c3852c71e984751c2c637..cd9f4376d4ef60a4c288d294eb3bca0ec1345b88 100644 --- a/src/plugins/value/domains/cvalue/cvalue_domain.ml +++ b/src/plugins/value/domains/cvalue/cvalue_domain.ml @@ -559,11 +559,13 @@ module State = struct let display_results () = Value_parameters.result "====== VALUES COMPUTED ======"; - Callgraph.Uses.iter_in_rev_order display; + Eva_dynamic.Callgraph.iter_in_rev_order display; Value_parameters.result "%t" Value_perf.display let post_analysis _state = - if Value_parameters.ForceValues.get () && Value_parameters.verbose_atleast 1 + if Value_parameters.ForceValues.get () + && Value_parameters.verbose_atleast 1 + && Plugin.is_present "inout" then Value_parameters.ForceValues.output display_results end diff --git a/src/plugins/value/engine/compute_functions.ml b/src/plugins/value/engine/compute_functions.ml index 718da24a52985bef50b701c9ca5e90154106c37e..89f505305e48128fbed9ca567db7db6b36124c7b 100644 --- a/src/plugins/value/engine/compute_functions.ml +++ b/src/plugins/value/engine/compute_functions.ml @@ -54,6 +54,12 @@ let options_ok () = Value_parameters.BuiltinsOverrides.iter (fun (kf, _) -> check_assigns kf); Value_parameters.UsePrototype.iter (fun kf -> check_assigns kf) +let plugins_ok () = + if not (Plugin.is_present "inout") then + Value_parameters.warning + "The inout plugin is missing: some features are disabled, \ + and the analysis may have degraded precision and performance." + (* Do something tasteless in case the user did not put a spec on functions for which he set [-eva-use-spec]: generate an incorrect one ourselves *) let generate_specs () = @@ -73,6 +79,7 @@ let generate_specs () = let pre_analysis () = floats_ok (); options_ok (); + plugins_ok (); Split_return.pretty_strategies (); generate_specs (); Widen.precompute_widen_hints (); @@ -108,10 +115,10 @@ let post_analysis () = (* Try to refine the 'Unknown' statuses that have been emitted during this analysis. *) Eval_annots.mark_green_and_red (); - Eval_annots.mark_rte (); + Eva_dynamic.RteGen.mark_generated_rte (); post_analysis_cleanup ~aborted:false; (* Remove redundant alarms *) - if Value_parameters.RmAssert.get () then !Db.Value.rm_asserts () + if Value_parameters.RmAssert.get () then Eva_dynamic.Scope.rm_asserts () (* Registers signal handlers for SIGUSR1 and SIGINT to cleanly abort the Eva analysis. Returns a function that restores previous signal behaviors after diff --git a/src/plugins/value/gui_files/register_gui.ml b/src/plugins/value/gui_files/register_gui.ml index 5adf217e9f95053da29b3c13851e32527318dae4..3587497948dafbc7d40353138da1651a5b8202c2 100644 --- a/src/plugins/value/gui_files/register_gui.ml +++ b/src/plugins/value/gui_files/register_gui.ml @@ -227,9 +227,7 @@ let gui_compute_values (main_ui:main_ui) = let cleaned_outputs kf s = let outs = Db.Outputs.kinstr (Kstmt s) in - let accept = - Callgraph.Uses.accept_base ~with_formals:true ~with_locals:true kf - in + let accept = Eva_dynamic.Callgraph.accept_base kf in let filter = Locations.Zone.filter_base accept in Option.map filter outs diff --git a/src/plugins/value/legacy/eval_annots.ml b/src/plugins/value/legacy/eval_annots.ml index cb3647e4fde810b6212ce0a8e0351d24e2ee3a2f..68aed0aadab7bc2b5171980bd0962f7b4f3e8c94 100644 --- a/src/plugins/value/legacy/eval_annots.ml +++ b/src/plugins/value/legacy/eval_annots.ml @@ -102,35 +102,6 @@ let mark_unreachable () = Annotations.iter_all_code_annot do_code_annot; Visitor.visitFramacFile unreach (Ast.get ()) -let mark_rte () = - let _, mem, _ = !Db.RteGen.get_memAccess_status () in - let _, arith, _ = !Db.RteGen.get_divMod_status () in - let _, signed_ovf, _ = !Db.RteGen.get_signedOv_status () in - let _, unsigned_ovf, _ = !Db.RteGen.get_unsignedOv_status () in - let _, signed_downcast, _ = !Db.RteGen.get_signed_downCast_status () in - let _, unsigned_downcast, _ = !Db.RteGen.get_unsignedDownCast_status () in - let _, pointer_call, _ = !Db.RteGen.get_pointerCall_status () in - let _, float_to_int, _ = !Db.RteGen.get_float_to_int_status () in - let _, finite_float, _ = !Db.RteGen.get_finite_float_status () in - let b_signed_ovf = Kernel.SignedOverflow.get () in - let b_unsigned_ovf = Kernel.UnsignedOverflow.get () in - let b_signed_downcast = Kernel.SignedDowncast.get () in - let b_unsigned_downcast = Kernel.UnsignedDowncast.get () in - Globals.Functions.iter - (fun kf -> - if !Db.Value.is_called kf then ( - mem kf true; - arith kf true; - pointer_call kf true; - if b_signed_ovf then signed_ovf kf true; - if b_unsigned_ovf then unsigned_ovf kf true; - if b_signed_downcast then signed_downcast kf true; - if b_unsigned_downcast then unsigned_downcast kf true; - float_to_int kf true; - finite_float kf true; - ) - ) - let c_labels kf cs = if !Db.Value.use_spec_instead_of_definition kf then Cil_datatype.Logic_label.Map.empty diff --git a/src/plugins/value/legacy/eval_annots.mli b/src/plugins/value/legacy/eval_annots.mli index 03fbb8c51541c594f3d7954bc53a77ce0460f303..ba43b7aa2f95bfa0d3198beef927964e5c40fb74 100644 --- a/src/plugins/value/legacy/eval_annots.mli +++ b/src/plugins/value/legacy/eval_annots.mli @@ -26,5 +26,4 @@ val has_requires: spec -> bool val mark_invalid_initializers: unit -> unit val mark_unreachable: unit -> unit val mark_green_and_red: unit -> unit -val mark_rte: unit -> unit val c_labels: kernel_function -> Value_types.callstack -> Eval_terms.labels_states diff --git a/src/plugins/value/utils/eva_dynamic.ml b/src/plugins/value/utils/eva_dynamic.ml new file mode 100644 index 0000000000000000000000000000000000000000..b62a8ec73cb2f5f61f8db4a83e434ccfcbc2f15b --- /dev/null +++ b/src/plugins/value/utils/eva_dynamic.ml @@ -0,0 +1,67 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2021 *) +(* 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 get ~plugin name typ ~fallback = + try Dynamic.get ~plugin name typ + with Failure _ | Dynamic.(Unbound_value _ | Incompatible_type _) -> fallback + +module Callgraph = struct + let plugin = "callgraph" + + let iter_in_rev_order f = + let fallback = Globals.Functions.iter in + let typ = Datatype.(func (func Kernel_function.ty unit) unit) in + get ~plugin "iter_in_rev_order" typ ~fallback f + + let accept_base kf v = + let fallback _ _ = true in + let typ = Datatype.(func2 Kernel_function.ty Base.ty bool) in + get ~plugin "accept_base" typ ~fallback kf v +end + +module Scope = struct + let plugin = "scope" + + let rm_asserts () = + let fallback () = + Value_parameters.warning + "The scope plugin is missing: cannot remove redundant alarms." + in + let typ = Datatype.(func unit unit) in + get ~plugin "rm_asserts" typ ~fallback () +end + +module RteGen = struct + let plugin = "RteGen" + + let all_statuses () = + let kf = Kernel_function.ty in + let typ = + Datatype.(list (triple string (func2 kf bool unit) (func kf bool))) + in + get ~plugin "all_statuses" typ ~fallback:[] + + let mark_generated_rte () = + let list = all_statuses () in + let mark kf = List.iter (fun (_kind, set, _get) -> set kf true) list in + Globals.Functions.iter (fun kf -> if !Db.Value.is_called kf then mark kf) +end diff --git a/src/plugins/value/utils/eva_dynamic.mli b/src/plugins/value/utils/eva_dynamic.mli new file mode 100644 index 0000000000000000000000000000000000000000..85648b915300cf697ce591ed119e748edad837ff --- /dev/null +++ b/src/plugins/value/utils/eva_dynamic.mli @@ -0,0 +1,43 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2021 *) +(* 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). *) +(* *) +(**************************************************************************) + +(** Access to other plugins API via {Dynamic.get}. *) + +module Callgraph: sig + (** Iterates over all functions in the callgraph in reverse order, i.e. from + callees to callers. If callgraph is missing, the order is unspecified. *) + val iter_in_rev_order: (Kernel_function.t -> unit) -> unit + + (** Returns [true] if [base] is a global, or a formal or local of either [kf] + or one of its callers. If callgraph is missing, always returns true. *) + val accept_base: Kernel_function.t -> Base.t -> bool +end + +module Scope: sig + (** Removes redundant assertions. Warns if the scope plugin is missing. *) + val rm_asserts: unit -> unit +end + +module RteGen: sig + (** Marks all RTE as generated. Does nothing if the rte plugin is missing. *) + val mark_generated_rte: unit -> unit +end diff --git a/tests/value/memexec.c b/tests/value/memexec.c index bb6bb912db9935c2a1a631b9b398d127236419f3..e87602726a13efd85890a02ab97e39e205d27042 100644 --- a/tests/value/memexec.c +++ b/tests/value/memexec.c @@ -1,7 +1,7 @@ /* run.config* - STDOPT: +"-rte-select fbug @RTE_TEST@ -then -eva" + PLUGIN: @PTEST_PLUGIN@ rtegen + STDOPT: #"-machdep x86_32 -rte-select fbug @RTE_TEST@ -then -eva" */ - int x1, y1, z1, z2; volatile int c, nondet; void f11() { diff --git a/tests/value/oracle/precond2.1.res.oracle b/tests/value/oracle/precond2.1.res.oracle index ff415fa2c9b324a73cad48fbd8cc4917553d342a..4787a711af49ec5c93398aa4513386bbb9d207e3 100644 --- a/tests/value/oracle/precond2.1.res.oracle +++ b/tests/value/oracle/precond2.1.res.oracle @@ -35,8 +35,6 @@ x ∈ {1} [eva:final-states] Values at end of function main: x ∈ {0; 1} -[rte:annot] annotating function f -[rte:annot] annotating function main [report] Computing properties status... -------------------------------------------------------------------------------- diff --git a/tests/value/oracle/summary.4.res.oracle b/tests/value/oracle/summary.4.res.oracle index 6faede6c061bc435ba56fa292654caf779bf975c..81eb244352197d5f99e3c7f35bb16ba46ccbe574 100644 --- a/tests/value/oracle/summary.4.res.oracle +++ b/tests/value/oracle/summary.4.res.oracle @@ -1,5 +1,3 @@ -[kernel] Warning: -slevel is a deprecated alias for option -eva-slevel. - Please use -eva-slevel instead. [kernel] Parsing summary.i (no preprocessing) [rte:annot] annotating function alarms [rte:annot] annotating function bottom @@ -8,6 +6,8 @@ [rte:annot] annotating function logic [rte:annot] annotating function main [rte:annot] annotating function minimal +[kernel] Warning: -slevel is a deprecated alias for option -eva-slevel. + Please use -eva-slevel instead. [eva] Analyzing a complete application starting at main [eva] Computing initial state [eva] Initial state computed @@ -107,7 +107,7 @@ ---------------------------------------------------------------------------- Some errors and warnings have been raised during the analysis: by the Eva analyzer: 0 errors 1 warning - by the Frama-C kernel: 0 errors 2 warnings + by the Frama-C kernel: 0 errors 3 warnings ---------------------------------------------------------------------------- 18 alarms generated by the analysis: 3 invalid memory accesses diff --git a/tests/value/oracle/unknown_sizeof.0.res.oracle b/tests/value/oracle/unknown_sizeof.0.res.oracle index b106b41c0ed6f8b83419377598478fedd74bcbfe..4244ff0a82bf4d678680de7005b49eb33ba7e264 100644 --- a/tests/value/oracle/unknown_sizeof.0.res.oracle +++ b/tests/value/oracle/unknown_sizeof.0.res.oracle @@ -1,4 +1,5 @@ [kernel] Parsing unknown_sizeof.i (no preprocessing) +[eva] Warning: The inout plugin is missing: some features are disabled, and the analysis may have degraded precision and performance. [eva] Analyzing a complete application starting at main1 [eva] Computing initial state [eva:unknown-size] unknown_sizeof.i:8: Warning: diff --git a/tests/value/oracle/unknown_sizeof.1.res.oracle b/tests/value/oracle/unknown_sizeof.1.res.oracle index 52d022abfce0070deb7ef6ef3f21e519c7411d0a..fd9e82d2f78f1e71419051cac7ceafad4710390f 100644 --- a/tests/value/oracle/unknown_sizeof.1.res.oracle +++ b/tests/value/oracle/unknown_sizeof.1.res.oracle @@ -1,4 +1,5 @@ [kernel] Parsing unknown_sizeof.i (no preprocessing) +[eva] Warning: The inout plugin is missing: some features are disabled, and the analysis may have degraded precision and performance. [eva] Analyzing a complete application starting at main2 [eva] Computing initial state [eva:unknown-size] unknown_sizeof.i:8: Warning: diff --git a/tests/value/summary.i b/tests/value/summary.i index 718f105808a8e7a74784f387e3945490e35f5f0b..3ef6022672e965f17208f8baaf7385d8cfc54c8b 100644 --- a/tests/value/summary.i +++ b/tests/value/summary.i @@ -3,8 +3,8 @@ STDOPT: +"-eva-msg-key=summary -main minimal" STDOPT: +"-eva-msg-key=summary -main bottom" STDOPT: +"-eva-msg-key=summary -main main" -PLUGIN: @PTEST_PLUGIN@ rtegen - STDOPT: +"@RTE_TEST@ -eva-msg-key=summary -main main -slevel 0" + PLUGIN: @PTEST_PLUGIN@ rtegen + OPT: -machdep x86_32 @RTE_TEST@ -then @EVA_TEST@ -eva-msg-key=summary -main main -slevel 0 */ /* Tests the summary on the smallest possible program. */ void minimalist ();