diff --git a/src/plugins/e-acsl/.gitignore b/src/plugins/e-acsl/.gitignore index a76fdee561c4288a70fd4b3473fd29e6caf5ef14..18775a69119b68f9bba8f09368c3653ef11a193f 100644 --- a/src/plugins/e-acsl/.gitignore +++ b/src/plugins/e-acsl/.gitignore @@ -57,6 +57,7 @@ /tests/runtime/*.cm* /tests/runtime/result/* /tests/temporal/result/* +/tests/special/result/* /tests/no-main/result/* /tests/full-mmodel/result/* /tests/bts/result/* diff --git a/src/plugins/e-acsl/Makefile.in b/src/plugins/e-acsl/Makefile.in index f587123e589abdeb13e35f45c7daec5dd496b81b..013bcefbcf7da9d4fd64bfc6ed2cde4294a2bff1 100644 --- a/src/plugins/e-acsl/Makefile.in +++ b/src/plugins/e-acsl/Makefile.in @@ -69,6 +69,7 @@ PLUGIN_CMO:= local_config \ exit_points \ label \ env \ + keep_status \ dup_functions \ interval \ typing \ @@ -129,7 +130,7 @@ $(EACSL_PLUGIN_DIR)/local_config.ml: $(EACSL_PLUGIN_DIR)/Makefile.in $(VERSION_F ifeq (@MAY_RUN_TESTS@,yes) -PLUGIN_TESTS_DIRS := reject runtime bts gmp no-main full-mmodel temporal +PLUGIN_TESTS_DIRS := reject runtime bts gmp no-main full-mmodel temporal special PLUGIN_TESTS_LIB := $(EACSL_PLUGIN_DIR)/tests/print.ml E_ACSL_TESTS: $(EACSL_PLUGIN_DIR)/tests/test_config diff --git a/src/plugins/e-acsl/doc/Changelog b/src/plugins/e-acsl/doc/Changelog index b080ed4c2a5a8b2c1632a6076814833e951b74ae..1fe2370039081e0179c86ab846df2a68d00d8abd 100644 --- a/src/plugins/e-acsl/doc/Changelog +++ b/src/plugins/e-acsl/doc/Changelog @@ -15,6 +15,8 @@ # E-ACSL: the Whole E-ACSL plug-in ############################################################################### +-* E-ACSL [2017/11/27] Restore behavior of option -e-acsl-valid broken + since Phosphorus (included). -* E-ACSL [2017/10/25] Fix bug #2303 about unnamed formals in annotated functions. - E-ACSL [2017/06/10] Add --free-valid-address option to e-acsl.gcc.sh diff --git a/src/plugins/e-acsl/dup_functions.ml b/src/plugins/e-acsl/dup_functions.ml index 9d330878ff321b82be59f130950bb863b3eb7ff5..9a74392d6f07d1c83b8aaeccf86dff4c4db1c004 100644 --- a/src/plugins/e-acsl/dup_functions.ml +++ b/src/plugins/e-acsl/dup_functions.ml @@ -29,7 +29,6 @@ let dkey = Options.dkey_dup (* ********************************************************************** *) let fct_tbl: unit Kernel_function.Hashtbl.t = Kernel_function.Hashtbl.create 7 -let is_generated kf = Kernel_function.Hashtbl.mem fct_tbl kf let actions = Queue.create () @@ -51,51 +50,10 @@ let reset () = Global.reset (); Queue.clear actions -(* ********************************************************************** *) -(* Duplicating property statuses *) -(* ********************************************************************** *) - -let reemit = function - | Property.IPBehavior _ | Property.IPAxiom _ | Property.IPAxiomatic _ - | Property.IPPredicate (Property.PKAssumes _, _, _, _) -> false - | _ -> true - -let copy_ppt old_prj new_prj old_ppt new_ppt = - let module P = Property_status in - let selection = State_selection.of_list [ P.self; Emitter.self ] in - let emit s l = - Project.on ~selection new_prj - (fun s -> - let e = match l with [] -> assert false | e :: _ -> e in - let emitter = Emitter.Usable_emitter.get e.P.emitter in - match s with - | P.True | P.False_and_reachable | P.Dont_know -> - P.emit emitter ~hyps:e.P.properties new_ppt s - | P.False_if_reachable -> - (* in that case, the only hypothesis is "Reachable new_ppt" which must - be automatically added by the kernel *) - P.emit emitter ~hyps:[] new_ppt P.False_if_reachable) - s - in - let copy () = - match Project.on ~selection old_prj P.get old_ppt with - | P.Never_tried -> () - | P.Best(s, l) -> emit s l - | P.Inconsistent i -> - emit P.True i.P.valid; - emit P.False_and_reachable i.P.invalid - in - if reemit old_ppt && not (Options.Valid.get ()) then Queue.add copy actions - (* ********************************************************************** *) (* Duplicating functions *) (* ********************************************************************** *) -let dup_spec_status old_prj kf new_kf old_spec new_spec = - let old_ppts = Property.ip_of_spec kf Kglobal ~active:[] old_spec in - let new_ppts = Property.ip_of_spec new_kf Kglobal ~active:[] new_spec in - List.iter2 (copy_ppt old_prj (Project.current ())) old_ppts new_ppts - let dup_funspec tbl bhv spec = (* Options.feedback "DUP SPEC %a" Cil.d_funspec spec;*) let o = object @@ -205,7 +163,7 @@ let dup_fundec loc spec bhv kf vi new_vi = sallstmts = []; sspec = new_spec } -let dup_global loc old_prj spec bhv kf vi new_vi = +let dup_global loc actions spec bhv kf vi new_vi = let name = vi.vname in Options.feedback ~dkey ~level:2 "entering in function %s" name; let fundec = dup_fundec loc spec bhv kf vi new_vi in @@ -216,8 +174,34 @@ let dup_global loc old_prj spec bhv kf vi new_vi = Globals.Functions.register new_kf; Globals.Functions.replace_by_definition new_spec fundec loc; Annotations.register_funspec new_kf; - dup_spec_status old_prj kf new_kf spec new_spec; Options.feedback ~dkey ~level:2 "function %s" name; + (* remove the specs attached to the previous kf iff it is a definition: + it is necessary to keep stable the number of annotations in order to get + [Keep_status] working fine. *) + let kf = Cil.get_kernel_function bhv kf in + if Kernel_function.is_definition kf then begin + Queue.add + (fun () -> + let bhvs = + Annotations.fold_behaviors (fun e b acc -> (e, b) :: acc) kf [] + in + List.iter + (fun (e, b) -> Annotations.remove_behavior ~force:true e kf b) + bhvs; + Annotations.iter_decreases + (fun e _ -> Annotations.remove_decreases e kf) + kf; + Annotations.iter_terminates + (fun e _ -> Annotations.remove_terminates e kf) + kf; + Annotations.iter_complete + (fun e l -> Annotations.remove_complete e kf l) + kf; + Annotations.iter_disjoint + (fun e l -> Annotations.remove_disjoint e kf l) + kf) + actions + end; GFun(fundec, loc), GFunDecl(new_spec, new_vi, loc) (* ********************************************************************** *) @@ -258,22 +242,7 @@ class dup_functions_visitor prj = object (self) | Memory_model -> before_memory_model <- Code | Code -> () - method !vcode_annot a = - Cil.JustCopyPost - (fun a' -> - let get_ppt kf stmt a = Property.ip_of_code_annot kf stmt a in - let kf = Extlib.the self#current_kf in - let stmt = Extlib.the self#current_stmt in - List.iter2 - (fun p p' -> copy_ppt (Project.current ()) prj p p') - (get_ppt kf stmt a) - (get_ppt - (Cil.get_kernel_function self#behavior kf) - (Cil.get_stmt self#behavior stmt) - a'); - a') - - method !vlogic_info_decl li = + method !vlogic_info_decl li = Global.add_logic_info li; Cil.JustCopy @@ -338,8 +307,15 @@ if there are memory-related annotations.@]" let spec = Annotations.funspec ~populate:false kf in let vi_bhv = Cil.get_varinfo self#behavior vi in let new_g, new_decl = - Project.on prj - (dup_global loc (Project.current ()) spec self#behavior kf vi_bhv) + Project.on + prj + (dup_global + loc + self#get_filling_actions + spec + self#behavior + kf + vi_bhv) new_vi in (* postpone the introduction of the new function definition to the diff --git a/src/plugins/e-acsl/dup_functions.mli b/src/plugins/e-acsl/dup_functions.mli index 3ac1e612b3fad6cbd09c1c0dd8b7f5bffedc8534..2f2b51bf6719c0924a0617352f89bc3a4fd945c8 100644 --- a/src/plugins/e-acsl/dup_functions.mli +++ b/src/plugins/e-acsl/dup_functions.mli @@ -20,10 +20,7 @@ (* *) (**************************************************************************) -open Cil_types - val dup: unit -> Project.t -val is_generated: kernel_function -> bool (* Local Variables: diff --git a/src/plugins/e-acsl/keep_status.ml b/src/plugins/e-acsl/keep_status.ml new file mode 100644 index 0000000000000000000000000000000000000000..684dc2307407b1e06d4b3f74032f5b587199f564 --- /dev/null +++ b/src/plugins/e-acsl/keep_status.ml @@ -0,0 +1,150 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2017 *) +(* 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). *) +(* *) +(**************************************************************************) + +(* E-ACSL needs to access to the property status of every property (in + particular for the option -e-acsl-valid). However, the necessary elements for + building a property are copied/modified several times from the original + project to the final project and the property statuses are destroyed when + creating the intermediate projects; so there is no easy way to access to + property statuses from the final project. + + This module aims at solving this issue by providing an access to property + statuses from the final project. To work properly, it requires to visit every + property during the final visit in the very same order than during the AST + preparation visit. Indeed, for each function, it associates to each + property an unique integer corresponding to its visit ordering. *) + +(* the kind is only used for a few additional consistency checks between [push] + and [must_translate]*) +type kind = + | K_Assert + | K_Invariant + | K_Variant + | K_StmtSpec + | K_Allocation + | K_Assigns + | K_Decreases + | K_Terminates + | K_Complete + | K_Disjoint + | K_Requires + | K_Ensures + +let pretty_kind fmt k = + Format.fprintf fmt "%s" + (match k with + | K_Assert -> "assert" + | K_Invariant -> "invariant" + | K_Variant -> "variant" + | K_StmtSpec -> "stmtspec" + | K_Allocation -> "allocation" + | K_Assigns -> "assigns" + | K_Decreases -> "decreases" + | K_Terminates -> "terminates" + | K_Complete -> "complete" + | K_Disjoint -> "disjoint" + | K_Requires -> "requires" + | K_Ensures -> "ensures") + +(* information attached to every kernel_function containing an annotation *) +type kf_info = + { mutable cpt: int; (* counter building the relationship between [push] and + [must_translate *) + mutable statuses: (kind * bool) Datatype.Int.Map.t + (* map associating a property as an integer to its kind and status + ([true] = proved) *) } + +(* statuses for each function represented by its name (because the [kf] itself + changes from a project to another). *) +let keep_status + : kf_info Datatype.String.Hashtbl.t + = Datatype.String.Hashtbl.create 17 + +(* will contain the value of a few options from the original project + in order to safely use them from the final project. *) +let option_valid = ref false +let option_check = ref false + +let clear () = + Datatype.String.Hashtbl.clear keep_status; + option_valid := Options.Valid.get (); + option_check := Options.Check.get () + +let push kf kind ppt = +(* Options.feedback "PUSHING %a for %a" + pretty_kind kind + Kernel_function.pretty kf;*) + (* no registration when -e-acsl-check or -e-acsl-valid *) + if not (!option_check || !option_valid) then + let keep = + let open Property_status in + match get ppt with + | Never_tried + | Inconsistent _ + | Best ((False_if_reachable | False_and_reachable | Dont_know), _) -> + true + | Best (True, _) -> + false + in + let status = kind, keep in + let name = Kernel_function.get_name kf in + try + let info = Datatype.String.Hashtbl.find keep_status name in + info.cpt <- info.cpt + 1; + info.statuses <- Datatype.Int.Map.add info.cpt status info.statuses + with Not_found -> + let info = { cpt = 1; statuses = Datatype.Int.Map.singleton 1 status } in + Datatype.String.Hashtbl.add keep_status name info + +let before_translation () = + (* reset all counters *) + Datatype.String.Hashtbl.iter (fun _ info -> info.cpt <- 0) keep_status + +let must_translate kf kind = +(* Options.feedback "GETTING %a for %a" + pretty_kind kind + Kernel_function.pretty kf;*) + !option_check + || + !option_valid + || + (* function contracts have been moved from the original function to its + duplicate by [Dup_function] but they are still associated to the original + function here *) + let name = Misc.get_original_name kf in + let info = + try Datatype.String.Hashtbl.find keep_status name + with Not_found -> + Options.fatal "[keep_status] unbound function" Datatype.String.pretty kf + in + info.cpt <- info.cpt + 1; + let kind', keep = + try Datatype.Int.Map.find info.cpt info.statuses + with Not_found -> + Options.fatal "[keep_status] unbound annotation (id %d)" info.cpt + in + (* check kind consistency in order to detect more abnormal behaviors *) + if kind <> kind' then + Options.fatal "[keep_status] incorrect kind '%a' (expected: '%a')" + pretty_kind kind + pretty_kind kind'; + keep diff --git a/src/plugins/e-acsl/keep_status.mli b/src/plugins/e-acsl/keep_status.mli new file mode 100644 index 0000000000000000000000000000000000000000..5b863270be7438368297921ff200f85207a1ee7b --- /dev/null +++ b/src/plugins/e-acsl/keep_status.mli @@ -0,0 +1,54 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2017 *) +(* 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). *) +(* *) +(**************************************************************************) + +(** Make the property statuses of the initial project accessible when + doing the main translation *) + +type kind = + | K_Assert + | K_Invariant + | K_Variant + | K_StmtSpec + | K_Allocation + | K_Assigns + | K_Decreases + | K_Terminates (* TODO: should be removed: not part of the E-ACSL subset *) + | K_Complete + | K_Disjoint + | K_Requires + | K_Ensures + +val clear: unit -> unit +(** to be called before any program transformation *) + +val push: Kernel_function.t -> kind -> Property.t -> unit +(** store the given property of the given kind for the given function *) + +val before_translation: unit -> unit +(** to be called just before the main translation *) + +val must_translate: Kernel_function.t -> kind -> bool +(** To be called just before transforming a property of the given kind for the + given function. + VERY IMPORTANT: the property of the n-th call to this function exactly + correspond to the n-th pushed property (see {!push}). + @return true if and only if the translation must occur. *) diff --git a/src/plugins/e-acsl/main.ml b/src/plugins/e-acsl/main.ml index 18115a3f14ee0aca703e44510f85435f7709210d..247fb18dc5bf9c2dc14d7fc2cad0d2bd9ee49705 100644 --- a/src/plugins/e-acsl/main.ml +++ b/src/plugins/e-acsl/main.ml @@ -135,7 +135,7 @@ module Resulting_projects = (struct let name = "E-ACSL resulting projects" let size = 7 - let dependencies = [ Ast.self ] + let dependencies = Ast.self :: Options.parameter_states end) let () = @@ -249,6 +249,7 @@ let change_printer = end let main () = + Keep_status.clear (); if Options.Run.get () then begin change_printer (); ignore (generate_code (Options.Project_name.get ())) diff --git a/src/plugins/e-acsl/misc.ml b/src/plugins/e-acsl/misc.ml index 8a646f14934195fbd8486dee51f35e1ff2c797a2..a2b7839793bd136c46d6529d522d08281cd4f158 100644 --- a/src/plugins/e-acsl/misc.ml +++ b/src/plugins/e-acsl/misc.ml @@ -138,7 +138,7 @@ let is_generated_kf kf = let name = Kernel_function.get_vi kf in is_generated_varinfo name -let get_orig_name kf = +let get_original_name kf = let name = Kernel_function.get_name kf in strip_prefix e_acsl_gen_prefix name @@ -164,7 +164,7 @@ let mk_e_acsl_guard ?(reverse=false) kind kf e p = (mk_api_name "assert") [ e; kind_to_string loc kind; - Cil.mkString ~loc (get_orig_name kf); + Cil.mkString ~loc (get_original_name kf); Cil.mkString ~loc msg; Cil.integer loc line ] diff --git a/src/plugins/e-acsl/misc.mli b/src/plugins/e-acsl/misc.mli index 437b1b98a3e627b6c01ff337994befbbc8b7627b..e4f11509b1639aa8909758474e256c4f6d0a50c6 100644 --- a/src/plugins/e-acsl/misc.mli +++ b/src/plugins/e-acsl/misc.mli @@ -122,6 +122,10 @@ val is_generated_literal_string_varinfo: varinfo -> bool val is_generated_kf: kernel_function -> bool (** Same as [is_generated_varinfo] but for kernel functions *) +val get_original_name: kernel_function -> string +(** @return the original basename of a function for generated functions, or the + identify for ungenerated ones. *) + (* Local Variables: compile-command: "make" diff --git a/src/plugins/e-acsl/options.ml b/src/plugins/e-acsl/options.ml index 726cf32f2065154ed69b84ff620c9648c0ab210d..0d0466fcba11a22d080f23ce8c43eb06ce4a1f3c 100644 --- a/src/plugins/e-acsl/options.ml +++ b/src/plugins/e-acsl/options.ml @@ -119,6 +119,13 @@ let version () = end let () = Cmdline.run_after_configuring_stage version +let parameter_states = + [ Valid.self; + Gmp_only.self; + Full_mmodel.self; + Builtins.self; + Temporal_validity.self] + let must_visit () = Run.get () || Check.get () let dkey_analysis = register_category "analysis" diff --git a/src/plugins/e-acsl/options.mli b/src/plugins/e-acsl/options.mli index bfd8342cf004a6a6de3a0d485f07e0c04c029fe9..09ec5522a344a2337edcbf04e33153d05e1fd633 100644 --- a/src/plugins/e-acsl/options.mli +++ b/src/plugins/e-acsl/options.mli @@ -32,6 +32,8 @@ module Project_name: Parameter_sig.String module Builtins: Parameter_sig.String_set module Temporal_validity: Parameter_sig.Bool +val parameter_states: State.t list + val must_visit: unit -> bool val dkey_analysis: Log.category diff --git a/src/plugins/e-acsl/prepare_ast.ml b/src/plugins/e-acsl/prepare_ast.ml index f67f04117572065772b9404fffd676847195177f..a0a20e405372bf19b61de04145bdf0acc0d9d411 100644 --- a/src/plugins/e-acsl/prepare_ast.ml +++ b/src/plugins/e-acsl/prepare_ast.ml @@ -58,7 +58,7 @@ let sufficiently_aligned attrs algn = let require_alignment typ attrs algn = Cil.bitsSizeOf typ < algn*8 && not (sufficiently_aligned attrs algn) -class prepare_visitor prj = object (_) +class prepare_visitor prj = object (self) inherit Visitor.frama_c_copy prj (* Add align attributes to local variables (required by temporal analysis) *) @@ -66,32 +66,153 @@ class prepare_visitor prj = object (_) if Temporal.is_enabled () then Cil.DoChildrenPost (fun blk -> List.iter (fun vi -> - (* 4 bytes alignment is required to allow sufficient space for storage - of 32-bit timestamps in a 1:1 shadow. *) + (* 4 bytes alignment is required to allow sufficient space for storage + of 32-bit timestamps in a 1:1 shadow. *) if require_alignment vi.vtype vi.vattr 4; then begin vi.vattr <- Attr("aligned",[AInt Integer.four]) :: vi.vattr end) - blk.blocals; - blk) + blk.blocals; + blk) else Cil.DoChildren + (* IMPORTANT: for keeping property statuses, we must preserve the ordering of + translation, see function [Translate.translate_pre_spec] and + [Translate.translate_post_spec]: be careful when modifying it. *) + + method private push_pre_spec s = + let kf = Extlib.the self#current_kf in + let kinstr = self#current_kinstr in + let open Keep_status in + Extlib.may + (fun v -> push kf K_Decreases (Property.ip_of_decreases kf kinstr v)) + s.spec_variant; + Extlib.may + (fun t -> push kf K_Terminates (Property.ip_of_terminates kf kinstr t)) + s.spec_terminates; + List.iter + (fun l -> + push kf K_Complete (Property.ip_of_complete kf kinstr ~active:[] l)) + s.spec_complete_behaviors; + List.iter + (fun l -> + push kf K_Disjoint (Property.ip_of_disjoint kf kinstr ~active:[] l)) + s.spec_disjoint_behaviors; + List.iter + (fun b -> + List.iter + (fun p -> push kf K_Requires (Property.ip_of_requires kf kinstr b p)) + b.b_requires) + s.spec_behavior + + method private push_post_spec spec = + let do_behavior b = + let kf = Extlib.the self#current_kf in + let ki = match self#current_stmt with + | None -> Kglobal + | Some stmt -> Kstmt stmt + in + let open Keep_status in + Extlib.may + (push kf K_Assigns) + (Property.ip_of_assigns + kf + ki + (Property.Id_contract (Datatype.String.Set.empty (* TODO *), b)) + b.b_assigns); + List.iter + (fun p -> push kf K_Ensures (Property.ip_of_ensures kf ki b p)) + b.b_post_cond + in + (* fix ordering of behaviors' iterations *) + let bhvs = + List.sort + (fun b1 b2 -> String.compare b1.b_name b2.b_name) + spec.spec_behavior + in + List.iter do_behavior bhvs + + method private push_pre_code_annot a = + let kf = Extlib.the self#current_kf in + let stmt = Extlib.the self#current_stmt in + let push_single k a = + Keep_status.push kf k (Property.ip_of_code_annot_single kf stmt a) + in + let open Keep_status in + match a.annot_content with + | AAssert _ -> push_single K_Assert a + | AStmtSpec(_ (* TODO *), s) -> self#push_pre_spec s + | AInvariant _ -> push_single K_Invariant a + | AVariant v -> + push kf K_Variant (Property.ip_of_decreases kf (Kstmt stmt) v) + | AAssigns _ -> + (* TODO: should be a postcondition, but considered as a unhandled + precondition in translate.ml right now; and we need to preserve the + same ordering *) + Extlib.may + (push kf K_Assigns) + (Property.ip_assigns_of_code_annot kf (Kstmt stmt) a) + | AAllocation(_ (* TODO *), alloc) -> + Extlib.may + (push kf K_Allocation) + (Property.ip_of_allocation kf (Kstmt stmt) (Property.Id_loop a) alloc) + | APragma _ -> () (* not yet translated *) + | AExtended _ -> () (* never translate extensions *) + + method private push_post_code_annot a = match a.annot_content with + | AStmtSpec(_ (* TODO *), s) -> self#push_post_spec s + | AAssert _ + | AInvariant _ + | AVariant _ + | AAssigns _ + | AAllocation _ + | APragma _ + | AExtended _ -> () + (* Move variable declared in the body of a switch statement to the outer scope *) - method !vstmt_aux _ = - Cil.DoChildrenPost (fun stmt -> - match stmt.skind with - | Switch(_,sw_blk,_,_) -> - let new_blk = Cil.mkBlock [ stmt ] in - let new_stmt = Cil.mkStmt (Block new_blk) in - new_blk.blocals <- sw_blk.blocals; - sw_blk.blocals <- []; - new_stmt - | _ -> stmt) - - initializer - Project.copy ~selection:(Parameter_state.get_selection ()) prj -end + method !vstmt_aux init_stmt = + Annotations.iter_code_annot + (fun _ a -> self#push_pre_code_annot a) + init_stmt; + Cil.DoChildrenPost + (fun stmt -> + Annotations.iter_code_annot + (fun _ a -> self#push_post_code_annot a) + init_stmt; + match stmt.skind with + | Switch(_,sw_blk,_,_) -> + let new_blk = Cil.mkBlock [ stmt ] in + let new_stmt = Cil.mkStmt (Block new_blk) in + new_blk.blocals <- sw_blk.blocals; + sw_blk.blocals <- []; + new_stmt + | _ -> stmt) + + method private is_unvariadic_function vi = + match Cil.unrollType vi.vtype with + | TFun(_, _, variadic, _) -> not variadic + | _ -> false + + method !vglob_aux = function + | GVarDecl(vi, loc) | GFunDecl(_, vi, loc) | GFun({ svar = vi }, loc) + when self#is_unvariadic_function vi + && not (Misc.is_library_loc loc) + && not (Cil.is_builtin vi) + -> + let kf = Extlib.the self#current_kf in + let s = Annotations.funspec ~populate:false kf in + Cil.DoChildrenPost + (fun f -> + self#push_pre_spec s; + self#push_post_spec s; + f) + | _ -> + Cil.DoChildren + + initializer Project.copy ~selection:(Parameter_state.get_selection ()) prj + + end let prepare () = Options.feedback ~level:2 "prepare AST for E-ACSL transformations"; diff --git a/src/plugins/e-acsl/prepare_ast.mli b/src/plugins/e-acsl/prepare_ast.mli index f1ad742fab66ef0efd035baa8121dd9c66fe97f0..29af15182ef7cfec6aead0718095d4c21aeb10c1 100644 --- a/src/plugins/e-acsl/prepare_ast.mli +++ b/src/plugins/e-acsl/prepare_ast.mli @@ -21,9 +21,10 @@ (**************************************************************************) (** Prepare AST for E-ACSL generation. - * So for this mudule performs the only task: - * - Move declarations of variables declared in the bodies of switch - * statements to upper scopes. -*) + + So for this mudule performs two tasks: + - move declarations of variables declared in the bodies of switch + statements to upper scopes; + - store what is necessary to translate in [Keep_status]. *) val prepare: unit -> Project.t diff --git a/src/plugins/e-acsl/tests/bts/oracle/bts1390.res.oracle b/src/plugins/e-acsl/tests/bts/oracle/bts1390.res.oracle index 44f7f5d0c9ee05e8447d0a5a0a549a6385cef47b..63d40a91360f0e872180541f239014e2138af477 100644 --- a/src/plugins/e-acsl/tests/bts/oracle/bts1390.res.oracle +++ b/src/plugins/e-acsl/tests/bts/oracle/bts1390.res.oracle @@ -1,6 +1,5 @@ [e-acsl] beginning translation. [e-acsl] translation done in project "e-acsl". FRAMAC_SHARE/e-acsl/e_acsl.h:94:[value] warning: function __e_acsl_assert: precondition got status unknown. -tests/bts/bts1390.c:13:[value] warning: function memchr, behavior not_exists: postcondition got status unknown. (Behavior may be inactive, no reduction performed.) tests/bts/bts1390.c:13:[value] warning: function __gen_e_acsl_memchr, behavior not_exists: postcondition got status unknown. (Behavior may be inactive, no reduction performed.) tests/bts/bts1390.c:18:[value] warning: out of bounds read. assert \valid_read(s); diff --git a/src/plugins/e-acsl/tests/bts/oracle/bts2192.res.oracle b/src/plugins/e-acsl/tests/bts/oracle/bts2192.res.oracle index fd4f79bbeeddfce2d1453e31edd9e45174ec8964..7ad53f43ba46316c8f4ae40bb595517ab42aee16 100644 --- a/src/plugins/e-acsl/tests/bts/oracle/bts2192.res.oracle +++ b/src/plugins/e-acsl/tests/bts/oracle/bts2192.res.oracle @@ -2,5 +2,7 @@ [e-acsl] warning: annotating undefined function `atoi': the generated program may miss memory instrumentation if there are memory-related annotations. +FRAMAC_SHARE/libc/stdlib.h:76:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. [e-acsl] translation done in project "e-acsl". FRAMAC_SHARE/e-acsl/e_acsl.h:94:[value] warning: function __e_acsl_assert: precondition got status unknown. diff --git a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1307.c b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1307.c index caa221c7af4e0b90fcc074663440e0a315d67ca1..bf5e66ec057ee972ef969f95c4fdff161a156f1d 100644 --- a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1307.c +++ b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1307.c @@ -12,16 +12,6 @@ */ void __gen_e_acsl_foo(float *Mtmax_in, float *Mwmax, float *Mtmax_out); -/*@ requires \valid(Mtmax_in); - requires \valid(Mwmax); - requires \valid(Mtmax_out); - - behavior OverEstimate_Motoring: - assumes \true; - ensures - *\old(Mtmax_out) ≡ - *\old(Mtmax_in) + (5 - ((5 / 80) * *\old(Mwmax)) * 0.4); - */ void foo(float *Mtmax_in, float *Mwmax, float *Mtmax_out) { __e_acsl_store_block((void *)(& Mtmax_out),(size_t)8); @@ -49,17 +39,6 @@ void foo(float *Mtmax_in, float *Mwmax, float *Mtmax_out) */ void __gen_e_acsl_bar(float *Mtmin_in, float *Mwmin, float *Mtmin_out); -/*@ requires \valid(Mtmin_in); - requires \valid(Mwmin); - requires \valid(Mtmin_out); - - behavior UnderEstimate_Motoring: - assumes \true; - ensures - *\old(Mtmin_out) ≡ *\old(Mtmin_in) < 0.85 * *\old(Mwmin)? - *\old(Mtmin_in) ≢ 0.: - 0.85 * *\old(Mwmin) ≢ 0.; - */ void bar(float *Mtmin_in, float *Mwmin, float *Mtmin_out) { __e_acsl_store_block((void *)(& Mtmin_out),(size_t)8); diff --git a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1324.c b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1324.c index 15d4cac23157437357e95845df2697bc0d418868..71e2577f0495344831130a35a68205d1d722703d 100644 --- a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1324.c +++ b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1324.c @@ -6,10 +6,6 @@ */ int __gen_e_acsl_sorted(int *t, int n); -/*@ behavior yes: - assumes ∀ int i; 0 < i < n ⇒ *(t + (i - 1)) ≤ *(t + i); - ensures \result ≡ 1; - */ int sorted(int *t, int n) { int __retres; diff --git a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1326.c b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1326.c index a42da3e57acdae4ac55af81018c081955c8454d1..7185b9bfd07b25badaf02101ba912c7bf58fb607 100644 --- a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1326.c +++ b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1326.c @@ -11,13 +11,6 @@ typedef int ArrayInt[5]; void __gen_e_acsl_atp_NORMAL_computeAverageAccel(ArrayInt *Accel, int *AverageAccel); -/*@ ensures - *\old(AverageAccel) ≡ - (((((*\old(Accel))[4] + (*\old(Accel))[3]) + (*\old(Accel))[2]) + - (*\old(Accel))[1]) - + (*\old(Accel))[0]) - / 5; - */ void atp_NORMAL_computeAverageAccel(ArrayInt *Accel, int *AverageAccel) { __e_acsl_store_block((void *)(& AverageAccel),(size_t)8); diff --git a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1395.c b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1395.c index 302c3300239726a0a820d3994caa18b325329cab..9a0f79b306fb0d4ca48e5d9378ec76722cad1a18 100644 --- a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1395.c +++ b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1395.c @@ -3,7 +3,6 @@ /*@ requires n > 0; */ int __gen_e_acsl_fact(int n); -/*@ requires n > 0; */ int fact(int n) { int __retres; diff --git a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1478.c b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1478.c index d7ada2c7115bd789170d9402edb44f320bf154f5..c8a9cb14b211e3c564949587c33bf5668dfe4c79 100644 --- a/src/plugins/e-acsl/tests/bts/oracle/gen_bts1478.c +++ b/src/plugins/e-acsl/tests/bts/oracle/gen_bts1478.c @@ -10,10 +10,6 @@ int global_i = 0; */ void __gen_e_acsl_loop(void); -/*@ requires global_i ≡ 0; - requires \valid(global_i_ptr); - requires global_i_ptr ≡ &global_i; - */ void loop(void) { return; diff --git a/src/plugins/e-acsl/tests/gmp/oracle/gen_at.c b/src/plugins/e-acsl/tests/gmp/oracle/gen_at.c index 50e175fcb044acba4e3d318107f89dc288c160a6..4ca30ec02ab347dc3f46813193f65902c9e8d7e9 100644 --- a/src/plugins/e-acsl/tests/gmp/oracle/gen_at.c +++ b/src/plugins/e-acsl/tests/gmp/oracle/gen_at.c @@ -4,7 +4,6 @@ int A = 0; /*@ ensures \at(A,Post) ≡ 3; */ void __gen_e_acsl_f(void); -/*@ ensures \at(A,Post) ≡ 3; */ void f(void) { int __gen_e_acsl_at_4; @@ -106,7 +105,6 @@ void g(int *p, int *q) /*@ ensures \result ≡ \old(x); */ int __gen_e_acsl_h(int x); -/*@ ensures \result ≡ \old(x); */ int h(int x) { __e_acsl_store_block((void *)(& x),(size_t)4); diff --git a/src/plugins/e-acsl/tests/gmp/oracle/gen_at2.c b/src/plugins/e-acsl/tests/gmp/oracle/gen_at2.c index 5b54cad0dde4309b9fc5cd75328f89681d8810fd..2031fd1929009beb0b6d0703dee14223bc4886e6 100644 --- a/src/plugins/e-acsl/tests/gmp/oracle/gen_at2.c +++ b/src/plugins/e-acsl/tests/gmp/oracle/gen_at2.c @@ -4,7 +4,6 @@ int A = 0; /*@ ensures \at(A,Post) ≡ 3; */ void __gen_e_acsl_f(void); -/*@ ensures \at(A,Post) ≡ 3; */ void f(void) { __e_acsl_mpz_t __gen_e_acsl_at_3; @@ -177,7 +176,6 @@ void g(int *p, int *q) /*@ ensures \result ≡ \old(x); */ int __gen_e_acsl_h(int x); -/*@ ensures \result ≡ \old(x); */ int h(int x) { __e_acsl_store_block((void *)(& x),(size_t)4); diff --git a/src/plugins/e-acsl/tests/runtime/oracle/ctype_macros.res.oracle b/src/plugins/e-acsl/tests/runtime/oracle/ctype_macros.res.oracle index fb79cdc60f5e835b8ddd42b063bdef8dcdc1db7c..d55ebd19849aec4566b46463b0f6b2f12cfcd735 100644 --- a/src/plugins/e-acsl/tests/runtime/oracle/ctype_macros.res.oracle +++ b/src/plugins/e-acsl/tests/runtime/oracle/ctype_macros.res.oracle @@ -4,6 +4,8 @@ if there are memory-related annotations. tests/runtime/ctype_macros.c:39:[e-acsl] warning: E-ACSL construct `disjoint behaviors' is not yet supported. Ignoring annotation. +FRAMAC_SHARE/libc/ctype.h:164:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. [e-acsl] translation done in project "e-acsl". FRAMAC_SHARE/libc/ctype.h:164:[value] warning: function __gen_e_acsl_isupper: precondition got status unknown. FRAMAC_SHARE/e-acsl/e_acsl.h:94:[value] warning: function __e_acsl_assert: precondition got status unknown. diff --git a/src/plugins/e-acsl/tests/runtime/oracle/gen_function_contract.c b/src/plugins/e-acsl/tests/runtime/oracle/gen_function_contract.c index 9c07803917ff166930e4aaab947b1ff10ebb2196..b8b425b657a046419140f6ad0c4e03f63840bc21 100644 --- a/src/plugins/e-acsl/tests/runtime/oracle/gen_function_contract.c +++ b/src/plugins/e-acsl/tests/runtime/oracle/gen_function_contract.c @@ -5,7 +5,6 @@ int Y = 2; /*@ ensures X ≡ 1; */ void __gen_e_acsl_f(void); -/*@ ensures X ≡ 1; */ void f(void) { X = 1; @@ -16,8 +15,6 @@ void f(void) ensures Y ≡ 2; */ void __gen_e_acsl_g(void); -/*@ ensures X ≡ 2; - ensures Y ≡ 2; */ void g(void) { X = 2; @@ -27,7 +24,6 @@ void g(void) /*@ requires X ≡ 2; */ void __gen_e_acsl_h(void); -/*@ requires X ≡ 2; */ void h(void) { X ++; @@ -38,8 +34,6 @@ void h(void) requires Y ≡ 2; */ void __gen_e_acsl_i(void); -/*@ requires X ≡ 3; - requires Y ≡ 2; */ void i(void) { X += Y; @@ -57,15 +51,6 @@ void i(void) */ void __gen_e_acsl_j(void); -/*@ behavior b1: - requires X ≡ 5; - ensures X ≡ 3; - - behavior b2: - requires X ≡ 3 + Y; - requires Y ≡ 2; - ensures X ≡ Y + 1; - */ void j(void) { X = 3; @@ -84,16 +69,6 @@ void j(void) */ void __gen_e_acsl_k(void); -/*@ behavior b1: - assumes X ≡ 1; - requires X ≡ 0; - - behavior b2: - assumes X ≡ 3; - assumes Y ≡ 2; - requires X ≡ 3; - requires X + Y ≡ 5; - */ void k(void) { X += Y; @@ -103,7 +78,6 @@ void k(void) /*@ ensures X ≡ 5; */ int __gen_e_acsl_l(void); -/*@ ensures X ≡ 5; */ int l(void) { /*@ assert Y ≡ 2; */ @@ -123,16 +97,6 @@ int l(void) */ void __gen_e_acsl_m(void); -/*@ behavior b1: - assumes X ≡ 7; - ensures X ≡ 95; - - behavior b2: - assumes X ≡ 5; - assumes Y ≡ 2; - ensures X ≡ 7; - ensures X ≡ \old(X) + Y; - */ void m(void) { X += Y; @@ -152,17 +116,6 @@ void m(void) */ void __gen_e_acsl_n(void); -/*@ requires X > 0; - requires X < 10; - - behavior b1: - assumes X ≡ 7; - ensures X ≡ 8; - - behavior b2: - assumes X ≡ 5; - ensures X ≡ 98; - */ void n(void) { X ++; diff --git a/src/plugins/e-acsl/tests/runtime/oracle/gen_labeled_stmt.c b/src/plugins/e-acsl/tests/runtime/oracle/gen_labeled_stmt.c index 291fb0d05552c82f665cb5feb9008df5f8e35393..5a9054e4599ca792ef6b39bd44874eac89b9dd02 100644 --- a/src/plugins/e-acsl/tests/runtime/oracle/gen_labeled_stmt.c +++ b/src/plugins/e-acsl/tests/runtime/oracle/gen_labeled_stmt.c @@ -4,7 +4,6 @@ int X = 0; /*@ ensures X ≡ 3; */ int main(void); -/*@ ensures X ≡ 3; */ int __gen_e_acsl_main(void) { int __retres; diff --git a/src/plugins/e-acsl/tests/runtime/oracle/gen_linear_search.c b/src/plugins/e-acsl/tests/runtime/oracle/gen_linear_search.c index 71d59a04e1783ac482a8725a2a34e6f0728e508a..14aa44c0aee38b3a7164c9279e72eb4ec0e13f4a 100644 --- a/src/plugins/e-acsl/tests/runtime/oracle/gen_linear_search.c +++ b/src/plugins/e-acsl/tests/runtime/oracle/gen_linear_search.c @@ -13,16 +13,6 @@ int A[10]; */ int __gen_e_acsl_search(int elt); -/*@ requires ∀ ℤ i; 0 ≤ i < 9 ⇒ A[i] ≤ A[i + 1]; - - behavior exists: - assumes ∃ ℤ j; 0 ≤ j < 10 ∧ A[j] ≡ elt; - ensures \result ≡ 1; - - behavior not_exists: - assumes ∀ ℤ j; 0 ≤ j < 10 ⇒ A[j] ≢ elt; - ensures \result ≡ 0; - */ int search(int elt) { int __retres; diff --git a/src/plugins/e-acsl/tests/runtime/oracle/gen_result.c b/src/plugins/e-acsl/tests/runtime/oracle/gen_result.c index e0791ac88cb29a81155f515ee9b2d1b302acc2cd..f2fa04cfb0fc425ef67bcc62838c348f123837ff 100644 --- a/src/plugins/e-acsl/tests/runtime/oracle/gen_result.c +++ b/src/plugins/e-acsl/tests/runtime/oracle/gen_result.c @@ -3,7 +3,6 @@ /*@ ensures \result ≡ (int)(\old(x) - \old(x)); */ int __gen_e_acsl_f(int x); -/*@ ensures \result ≡ (int)(\old(x) - \old(x)); */ int f(int x) { x = 0; @@ -14,7 +13,6 @@ int Y = 1; /*@ ensures \result ≡ Y; */ int __gen_e_acsl_g(int x); -/*@ ensures \result ≡ Y; */ int g(int x) { return x; @@ -23,7 +21,6 @@ int g(int x) /*@ ensures \result ≡ 0; */ int __gen_e_acsl_h(void); -/*@ ensures \result ≡ 0; */ int h(void) { int __retres; diff --git a/src/plugins/e-acsl/tests/runtime/oracle/linear_search.res.oracle b/src/plugins/e-acsl/tests/runtime/oracle/linear_search.res.oracle index 535deea6a82d7ec6c5b4d05e868a04a634798c36..84e47332b50fc927bca65abef979455f04de93f7 100644 --- a/src/plugins/e-acsl/tests/runtime/oracle/linear_search.res.oracle +++ b/src/plugins/e-acsl/tests/runtime/oracle/linear_search.res.oracle @@ -2,10 +2,7 @@ [e-acsl] translation done in project "e-acsl". tests/runtime/linear_search.i:7:[value] warning: function __gen_e_acsl_search: precondition got status unknown. FRAMAC_SHARE/e-acsl/e_acsl.h:94:[value] warning: function __e_acsl_assert: precondition got status unknown. -tests/runtime/linear_search.i:7:[value] warning: function search: precondition got status unknown. tests/runtime/linear_search.i:18:[value] warning: loop invariant got status unknown. -tests/runtime/linear_search.i:10:[value] warning: function search, behavior exists: postcondition got status invalid. (Behavior may be inactive, no reduction performed.) -tests/runtime/linear_search.i:13:[value] warning: function search, behavior not_exists: postcondition got status invalid. (Behavior may be inactive, no reduction performed.) tests/runtime/linear_search.i:10:[value] warning: function __gen_e_acsl_search, behavior exists: postcondition got status unknown. (Behavior may be inactive, no reduction performed.) tests/runtime/linear_search.i:13:[value] warning: function __gen_e_acsl_search, behavior not_exists: postcondition got status unknown. (Behavior may be inactive, no reduction performed.) tests/runtime/linear_search.i:31:[value] warning: assertion got status unknown. diff --git a/src/plugins/e-acsl/tests/runtime/oracle/local_goto.res.oracle b/src/plugins/e-acsl/tests/runtime/oracle/local_goto.res.oracle index dee7ed535006155a87063f244e8b989a5985ef8e..a17600f826d5e9e8a2f8a4900495fcae1b11e574 100644 --- a/src/plugins/e-acsl/tests/runtime/oracle/local_goto.res.oracle +++ b/src/plugins/e-acsl/tests/runtime/oracle/local_goto.res.oracle @@ -10,9 +10,15 @@ if there are memory-related annotations. tests/runtime/local_goto.c:37:[e-acsl] warning: E-ACSL construct `logic function application' is not yet supported. Ignoring annotation. +tests/runtime/local_goto.c:37:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. tests/runtime/local_goto.c:28:[e-acsl] warning: E-ACSL construct `logic function application' is not yet supported. Ignoring annotation. +tests/runtime/local_goto.c:28:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. tests/runtime/local_goto.c:16:[e-acsl] warning: E-ACSL construct `logic function application' is not yet supported. Ignoring annotation. +tests/runtime/local_goto.c:16:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. [e-acsl] translation done in project "e-acsl". FRAMAC_SHARE/e-acsl/e_acsl.h:94:[value] warning: function __e_acsl_assert: precondition got status unknown. diff --git a/src/plugins/e-acsl/tests/special/e-acsl-valid.c b/src/plugins/e-acsl/tests/special/e-acsl-valid.c new file mode 100644 index 0000000000000000000000000000000000000000..be1694738022e2984871d08c645726b2a932739f --- /dev/null +++ b/src/plugins/e-acsl/tests/special/e-acsl-valid.c @@ -0,0 +1,41 @@ +/* run.config + COMMENT: test option -e-acsl-no-valid + LOG: gen_@PTEST_NAME@.c + OPT: -e-acsl-prepare -val -value-verbose 0 -machdep gcc_x86_64 -then -check -e-acsl-valid -e-acsl -then-last -load-script tests/print.cmxs -print -ocode tests/special/result/gen_@PTEST_NAME@.c -kernel-verbose 0 -value-verbose 0 + EXECNOW: ./scripts/testrun.sh @PTEST_NAME@ special "" "--frama-c=@frama-c@" + LOG: gen_@PTEST_NAME@2.c + OPT: -e-acsl-prepare -val -value-verbose 0 -machdep gcc_x86_64 -then -check -e-acsl-no-valid -e-acsl -then-last -load-script tests/print.cmxs -print -ocode tests/special/result/gen_@PTEST_NAME@2.c -kernel-verbose 0 -value-verbose 0 +*/ + +#include <stdlib.h> + +/*@ requires \valid(y); + @ requires *x >= 0; + @ ensures *x == \old(*x)+1; + @ assigns *x \from *x,x; + @ behavior b1: + @ assumes *y == 1; + @ assigns \nothing; + @ ensures *x < 0; + @ behavior b2: + @ assumes *x == 0; + @ ensures *x == 1; + @ complete behaviors; + @ disjoint behaviors b1, b2; + @ */ +void f(int *x, int *y) { + /*@ requires *x >= 0; + @ ensures 2 >= 1; + @ assigns *x; */ + { (*x)++; } + /*@ loop invariant 0 <= i <= 1; + @ loop variant 2 - i; */ + for(int i = 0; i < 1; i++) /*@ assert 1 == 1; */ /*@ assert \valid(y); */ ; +} + +int main(void) { + int x = 0; + int *y = (int *)malloc(sizeof(int)); + f(&x, y); + return 0; +} diff --git a/src/plugins/e-acsl/tests/special/oracle/builtin.0.res.oracle b/src/plugins/e-acsl/tests/special/oracle/builtin.0.res.oracle index 44e9bd786985b1ba4cae2d2237a2b982b30e91e5..274bdbe69e1a2b66be3ef24030464585c4d743f5 100644 --- a/src/plugins/e-acsl/tests/special/oracle/builtin.0.res.oracle +++ b/src/plugins/e-acsl/tests/special/oracle/builtin.0.res.oracle @@ -1,9 +1,5 @@ -[kernel] Parsing FRAMAC_SHARE/libc/__fc_builtin_for_normalization.i (no preprocessing) -[kernel] Parsing FRAMAC_SHARE/e-acsl/e_acsl.h (with preprocessing) -[kernel] Parsing FRAMAC_SHARE/e-acsl/e_acsl_gmp_types.h (with preprocessing) -[kernel] Parsing FRAMAC_SHARE/e-acsl/e_acsl_gmp.h (with preprocessing) +[kernel] Parsing FRAMAC_SHARE/e-acsl/e_acsl_gmp_api.h (with preprocessing) [kernel] Parsing FRAMAC_SHARE/e-acsl/e_acsl.h (with preprocessing) [kernel] Parsing tests/special/builtin.i (no preprocessing) [e-acsl] beginning translation. -FRAMAC_SHARE/libc/stdlib.h:160:[kernel] warning: No code nor implicit assigns clause for function calloc, generating default assigns from the prototype [e-acsl] translation done in project "e-acsl". diff --git a/src/plugins/e-acsl/tests/special/oracle/builtin.1.res.oracle b/src/plugins/e-acsl/tests/special/oracle/builtin.1.res.oracle index 44e9bd786985b1ba4cae2d2237a2b982b30e91e5..274bdbe69e1a2b66be3ef24030464585c4d743f5 100644 --- a/src/plugins/e-acsl/tests/special/oracle/builtin.1.res.oracle +++ b/src/plugins/e-acsl/tests/special/oracle/builtin.1.res.oracle @@ -1,9 +1,5 @@ -[kernel] Parsing FRAMAC_SHARE/libc/__fc_builtin_for_normalization.i (no preprocessing) -[kernel] Parsing FRAMAC_SHARE/e-acsl/e_acsl.h (with preprocessing) -[kernel] Parsing FRAMAC_SHARE/e-acsl/e_acsl_gmp_types.h (with preprocessing) -[kernel] Parsing FRAMAC_SHARE/e-acsl/e_acsl_gmp.h (with preprocessing) +[kernel] Parsing FRAMAC_SHARE/e-acsl/e_acsl_gmp_api.h (with preprocessing) [kernel] Parsing FRAMAC_SHARE/e-acsl/e_acsl.h (with preprocessing) [kernel] Parsing tests/special/builtin.i (no preprocessing) [e-acsl] beginning translation. -FRAMAC_SHARE/libc/stdlib.h:160:[kernel] warning: No code nor implicit assigns clause for function calloc, generating default assigns from the prototype [e-acsl] translation done in project "e-acsl". diff --git a/src/plugins/e-acsl/tests/special/oracle/e-acsl-valid.0.err.oracle b/src/plugins/e-acsl/tests/special/oracle/e-acsl-valid.0.err.oracle new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/plugins/e-acsl/tests/special/oracle/e-acsl-valid.0.res.oracle b/src/plugins/e-acsl/tests/special/oracle/e-acsl-valid.0.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..41f53a3b493062ae9708bbe2efe3c53d374afb70 --- /dev/null +++ b/src/plugins/e-acsl/tests/special/oracle/e-acsl-valid.0.res.oracle @@ -0,0 +1,15 @@ +tests/special/e-acsl-valid.c:12:[value] warning: function f: precondition got status unknown. +tests/special/e-acsl-valid.c:19:[value] warning: function f, behavior b1: postcondition got status invalid. (Behavior may be inactive, no reduction performed.) +[e-acsl] beginning translation. +tests/special/e-acsl-valid.c:27:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. +tests/special/e-acsl-valid.c:28:[e-acsl] warning: E-ACSL construct `variant' is not yet supported. Ignoring annotation. +tests/special/e-acsl-valid.c:31:[e-acsl] warning: E-ACSL construct `complete behaviors' is not yet supported. + Ignoring annotation. +tests/special/e-acsl-valid.c:31:[e-acsl] warning: E-ACSL construct `disjoint behaviors' is not yet supported. + Ignoring annotation. +tests/special/e-acsl-valid.c:13:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. +tests/special/e-acsl-valid.c:22:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. +[e-acsl] translation done in project "e-acsl". diff --git a/src/plugins/e-acsl/tests/special/oracle/e-acsl-valid.1.err.oracle b/src/plugins/e-acsl/tests/special/oracle/e-acsl-valid.1.err.oracle new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/plugins/e-acsl/tests/special/oracle/e-acsl-valid.1.res.oracle b/src/plugins/e-acsl/tests/special/oracle/e-acsl-valid.1.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..95252981ffa598a1e6178a56b390ee677d80598a --- /dev/null +++ b/src/plugins/e-acsl/tests/special/oracle/e-acsl-valid.1.res.oracle @@ -0,0 +1,15 @@ +tests/special/e-acsl-valid.c:12:[value] warning: function f: precondition got status unknown. +tests/special/e-acsl-valid.c:19:[value] warning: function f, behavior b1: postcondition got status invalid. (Behavior may be inactive, no reduction performed.) +[e-acsl] beginning translation. +tests/special/e-acsl-valid.c:27:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. +tests/special/e-acsl-valid.c:28:[e-acsl] warning: E-ACSL construct `variant' is not yet supported. Ignoring annotation. +tests/special/e-acsl-valid.c:28:[e-acsl] warning: E-ACSL construct `complete behaviors' is not yet supported. + Ignoring annotation. +tests/special/e-acsl-valid.c:28:[e-acsl] warning: E-ACSL construct `disjoint behaviors' is not yet supported. + Ignoring annotation. +tests/special/e-acsl-valid.c:12:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. +tests/special/e-acsl-valid.c:19:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. +[e-acsl] translation done in project "e-acsl". diff --git a/src/plugins/e-acsl/tests/special/oracle/gen_builtin.c b/src/plugins/e-acsl/tests/special/oracle/gen_builtin.c index 61c87805321645f1e886911b11e355a704edf69d..5119fca23dca60be72f4bffe6d695bdc26b1db2c 100644 --- a/src/plugins/e-acsl/tests/special/oracle/gen_builtin.c +++ b/src/plugins/e-acsl/tests/special/oracle/gen_builtin.c @@ -1,14 +1,13 @@ /* Generated by Frama-C */ +#include "stdlib.h" int incr(int x); /*@ ensures \result ≡ incr(\old(i)); */ int __gen_e_acsl_f(int i); -/*@ ensures \result ≡ incr(\old(i)); */ int f(int i) { - int j; - j = i + 1; + int j = i + 1; return j; } @@ -22,8 +21,8 @@ int incr(int x) int main(void) { int __retres; - int i; - i = __gen_e_acsl_f(2); + __e_acsl_memory_init((int *)0,(char ***)0,(size_t)8); + int i = __gen_e_acsl_f(2); __retres = 0; return __retres; } diff --git a/src/plugins/e-acsl/tests/special/oracle/gen_builtin2.c b/src/plugins/e-acsl/tests/special/oracle/gen_builtin2.c index aa17b64f55f75476367f21007df9ae54eb47a823..f5fefba9aecb54b313f94ea0be09eccc55497cd8 100644 --- a/src/plugins/e-acsl/tests/special/oracle/gen_builtin2.c +++ b/src/plugins/e-acsl/tests/special/oracle/gen_builtin2.c @@ -1,14 +1,13 @@ /* Generated by Frama-C */ +#include "stdlib.h" int incr(int x); /*@ ensures \result ≡ incr(\old(i)); */ int __gen_e_acsl_f(int i); -/*@ ensures \result ≡ incr(\old(i)); */ int f(int i) { - int j; - j = i + 1; + int j = i + 1; return j; } @@ -22,8 +21,8 @@ int incr(int x) int main(void) { int __retres; - int i; - i = __gen_e_acsl_f(2); + __e_acsl_memory_init((int *)0,(char ***)0,(size_t)8); + int i = __gen_e_acsl_f(2); __retres = 0; return __retres; } @@ -36,15 +35,15 @@ int __gen_e_acsl_f(int i) __gen_e_acsl_at = i; __retres = f(i); { - mpz_t __gen_e_acsl_result; + __e_acsl_mpz_t __gen_e_acsl_result; int __gen_e_acsl_incr_app; - mpz_t __gen_e_acsl_app; + __e_acsl_mpz_t __gen_e_acsl_app; int __gen_e_acsl_eq; __gmpz_init_set_si(__gen_e_acsl_result,(long)__retres); __gen_e_acsl_incr_app = incr(__gen_e_acsl_at); __gmpz_init_set_si(__gen_e_acsl_app,(long)__gen_e_acsl_incr_app); - __gen_e_acsl_eq = __gmpz_cmp((__mpz_struct const *)(__gen_e_acsl_result), - (__mpz_struct const *)(__gen_e_acsl_app)); + __gen_e_acsl_eq = __gmpz_cmp((__e_acsl_mpz_struct const *)(__gen_e_acsl_result), + (__e_acsl_mpz_struct const *)(__gen_e_acsl_app)); __e_acsl_assert(__gen_e_acsl_eq == 0,(char *)"Postcondition",(char *)"f", (char *)"\\result == incr(\\old(i))",12); __gmpz_clear(__gen_e_acsl_result); diff --git a/src/plugins/e-acsl/tests/special/oracle/gen_e-acsl-valid.c b/src/plugins/e-acsl/tests/special/oracle/gen_e-acsl-valid.c new file mode 100644 index 0000000000000000000000000000000000000000..9ec0221d8cca64df660dad187a97436976d01596 --- /dev/null +++ b/src/plugins/e-acsl/tests/special/oracle/gen_e-acsl-valid.c @@ -0,0 +1,208 @@ +/* Generated by Frama-C */ +#include "stdlib.h" +/*@ requires \valid(y); + requires *x ≥ 0; + ensures *\old(x) ≡ \old(*x) + 1; + assigns *x; + assigns *x \from *x, x; + + behavior b1: + assumes *y ≡ 1; + ensures *\old(x) < 0; + assigns \nothing; + + behavior b2: + assumes *x ≡ 0; + ensures *\old(x) ≡ 1; + + complete behaviors b2, b1; + disjoint behaviors b1, b2; + */ +void __gen_e_acsl_f(int *x, int *y); + +void f(int *x, int *y) +{ + /*@ requires *x ≥ 0; + ensures 2 ≥ 1; + assigns *x; */ + { + { + int __gen_e_acsl_valid_read; + __e_acsl_store_block((void *)(& y),(size_t)8); + __e_acsl_store_block((void *)(& x),(size_t)8); + __gen_e_acsl_valid_read = __e_acsl_valid_read((void *)x,sizeof(int), + (void *)x,(void *)(& x)); + __e_acsl_assert(__gen_e_acsl_valid_read,(char *)"RTE",(char *)"f", + (char *)"mem_access: \\valid_read(x)",27); + __e_acsl_assert(*x >= 0,(char *)"Precondition",(char *)"f", + (char *)"*x >= 0",27); + } + __e_acsl_initialize((void *)x,sizeof(int)); + (*x) ++; + __e_acsl_assert(2 >= 1,(char *)"Postcondition",(char *)"f", + (char *)"2 >= 1",28); + } + { + int i = 0; + /*@ loop variant 2 - i; */ + { + { + int __gen_e_acsl_and; + if (0 <= i) __gen_e_acsl_and = i <= 1; else __gen_e_acsl_and = 0; + __e_acsl_assert(__gen_e_acsl_and,(char *)"Invariant",(char *)"f", + (char *)"0 <= i <= 1",31); + } + /*@ loop invariant 0 ≤ i ≤ 1; */ + while (i < 1) { + /*@ assert 1 ≡ 1; */ + __e_acsl_assert(1 == 1,(char *)"Assertion",(char *)"f", + (char *)"1 == 1",33); + /*@ assert \valid(y); */ + { + int __gen_e_acsl_valid; + __gen_e_acsl_valid = __e_acsl_valid((void *)y,sizeof(int), + (void *)y,(void *)(& y)); + __e_acsl_assert(__gen_e_acsl_valid,(char *)"Assertion",(char *)"f", + (char *)"\\valid(y)",33); + } + { + int __gen_e_acsl_and_2; + i ++; + if (0 <= i) __gen_e_acsl_and_2 = i <= 1; + else __gen_e_acsl_and_2 = 0; + __e_acsl_assert(__gen_e_acsl_and_2,(char *)"Invariant",(char *)"f", + (char *)"0 <= i <= 1",31); + } + } + } + } + __e_acsl_delete_block((void *)(& y)); + __e_acsl_delete_block((void *)(& x)); + return; +} + +int main(void) +{ + int __retres; + __e_acsl_memory_init((int *)0,(char ***)0,(size_t)8); + int x = 0; + __e_acsl_store_block((void *)(& x),(size_t)4); + __e_acsl_full_init((void *)(& x)); + int *y = malloc(sizeof(int)); + __e_acsl_store_block((void *)(& y),(size_t)8); + __e_acsl_full_init((void *)(& y)); + __gen_e_acsl_f(& x,y); + __retres = 0; + __e_acsl_delete_block((void *)(& y)); + __e_acsl_delete_block((void *)(& x)); + __e_acsl_memory_clean(); + return __retres; +} + +/*@ requires \valid(y); + requires *x ≥ 0; + ensures *\old(x) ≡ \old(*x) + 1; + assigns *x; + assigns *x \from *x, x; + + behavior b1: + assumes *y ≡ 1; + ensures *\old(x) < 0; + assigns \nothing; + + behavior b2: + assumes *x ≡ 0; + ensures *\old(x) ≡ 1; + + complete behaviors b2, b1; + disjoint behaviors b1, b2; + */ +void __gen_e_acsl_f(int *x, int *y) +{ + long __gen_e_acsl_at_6; + int *__gen_e_acsl_at_5; + int *__gen_e_acsl_at_4; + int __gen_e_acsl_at_3; + int *__gen_e_acsl_at_2; + int __gen_e_acsl_at; + { + int __gen_e_acsl_valid; + __e_acsl_store_block((void *)(& y),(size_t)8); + __e_acsl_store_block((void *)(& x),(size_t)8); + __gen_e_acsl_valid = __e_acsl_valid((void *)y,sizeof(int),(void *)y, + (void *)(& y)); + __e_acsl_assert(__gen_e_acsl_valid,(char *)"Precondition",(char *)"f", + (char *)"\\valid(y)",12); + __e_acsl_assert(*x >= 0,(char *)"Precondition",(char *)"f", + (char *)"*x >= 0",13); + } + { + int __gen_e_acsl_valid_read_5; + __gen_e_acsl_valid_read_5 = __e_acsl_valid_read((void *)x,sizeof(int), + (void *)x,(void *)(& x)); + __e_acsl_assert(__gen_e_acsl_valid_read_5,(char *)"RTE",(char *)"f", + (char *)"mem_access: \\valid_read(x)",14); + __gen_e_acsl_at_6 = (long)*x; + } + __gen_e_acsl_at_5 = x; + __gen_e_acsl_at_4 = x; + { + int __gen_e_acsl_valid_read_3; + __gen_e_acsl_valid_read_3 = __e_acsl_valid_read((void *)x,sizeof(int), + (void *)x,(void *)(& x)); + __e_acsl_assert(__gen_e_acsl_valid_read_3,(char *)"RTE",(char *)"f", + (char *)"mem_access: \\valid_read(x)",21); + __gen_e_acsl_at_3 = *x == 0; + } + __gen_e_acsl_at_2 = x; + { + int __gen_e_acsl_valid_read; + __gen_e_acsl_valid_read = __e_acsl_valid_read((void *)y,sizeof(int), + (void *)y,(void *)(& y)); + __e_acsl_assert(__gen_e_acsl_valid_read,(char *)"RTE",(char *)"f", + (char *)"mem_access: \\valid_read(y)",17); + __gen_e_acsl_at = *y == 1; + } + f(x,y); + { + int __gen_e_acsl_implies; + int __gen_e_acsl_implies_2; + if (! __gen_e_acsl_at) __gen_e_acsl_implies = 1; + else { + int __gen_e_acsl_valid_read_2; + __gen_e_acsl_valid_read_2 = __e_acsl_valid_read((void *)__gen_e_acsl_at_2, + sizeof(int), + (void *)__gen_e_acsl_at_2, + (void *)(& __gen_e_acsl_at_2)); + __e_acsl_assert(__gen_e_acsl_valid_read_2,(char *)"RTE",(char *)"f", + (char *)"mem_access: \\valid_read(__gen_e_acsl_at_2)", + 19); + __gen_e_acsl_implies = *__gen_e_acsl_at_2 < 0; + } + __e_acsl_assert(__gen_e_acsl_implies,(char *)"Postcondition",(char *)"f", + (char *)"\\old(*y == 1) ==> *\\old(x) < 0",19); + if (! __gen_e_acsl_at_3) __gen_e_acsl_implies_2 = 1; + else { + int __gen_e_acsl_valid_read_4; + __gen_e_acsl_valid_read_4 = __e_acsl_valid_read((void *)__gen_e_acsl_at_4, + sizeof(int), + (void *)__gen_e_acsl_at_4, + (void *)(& __gen_e_acsl_at_4)); + __e_acsl_assert(__gen_e_acsl_valid_read_4,(char *)"RTE",(char *)"f", + (char *)"mem_access: \\valid_read(__gen_e_acsl_at_4)", + 22); + __gen_e_acsl_implies_2 = *__gen_e_acsl_at_4 == 1; + } + __e_acsl_assert(__gen_e_acsl_implies_2,(char *)"Postcondition", + (char *)"f",(char *)"\\old(*x == 0) ==> *\\old(x) == 1", + 22); + __e_acsl_assert(*__gen_e_acsl_at_5 == __gen_e_acsl_at_6 + 1L, + (char *)"Postcondition",(char *)"f", + (char *)"*\\old(x) == \\old(*x) + 1",14); + __e_acsl_delete_block((void *)(& y)); + __e_acsl_delete_block((void *)(& x)); + return; + } +} + + diff --git a/src/plugins/e-acsl/tests/special/oracle/gen_e-acsl-valid2.c b/src/plugins/e-acsl/tests/special/oracle/gen_e-acsl-valid2.c new file mode 100644 index 0000000000000000000000000000000000000000..dd54c01842d2331d7fd1b23586089b8cc434dd17 --- /dev/null +++ b/src/plugins/e-acsl/tests/special/oracle/gen_e-acsl-valid2.c @@ -0,0 +1,141 @@ +/* Generated by Frama-C */ +#include "stdlib.h" +/*@ requires \valid(y); + requires *x ≥ 0; + ensures *\old(x) ≡ \old(*x) + 1; + assigns *x; + assigns *x \from *x, x; + + behavior b1: + assumes *y ≡ 1; + ensures *\old(x) < 0; + assigns \nothing; + + behavior b2: + assumes *x ≡ 0; + ensures *\old(x) ≡ 1; + + complete behaviors b2, b1; + disjoint behaviors b1, b2; + */ +void __gen_e_acsl_f(int *x, int *y); + +void f(int *x, int *y) +{ + /*@ requires *x ≥ 0; + ensures 2 ≥ 1; + assigns *x; */ + { + { + int __gen_e_acsl_valid_read; + __e_acsl_store_block((void *)(& y),(size_t)8); + __e_acsl_store_block((void *)(& x),(size_t)8); + __gen_e_acsl_valid_read = __e_acsl_valid_read((void *)x,sizeof(int), + (void *)x,(void *)(& x)); + __e_acsl_assert(__gen_e_acsl_valid_read,(char *)"RTE",(char *)"f", + (char *)"mem_access: \\valid_read(x)",27); + __e_acsl_assert(*x >= 0,(char *)"Precondition",(char *)"f", + (char *)"*x >= 0",27); + } + __e_acsl_initialize((void *)x,sizeof(int)); + (*x) ++; + __e_acsl_assert(2 >= 1,(char *)"Postcondition",(char *)"f", + (char *)"2 >= 1",28); + } + { + int i = 0; + /*@ loop invariant 0 ≤ i ≤ 1; + loop variant 2 - i; */ + while (i < 1) { + /*@ assert 1 ≡ 1; */ ; + /*@ assert \valid(y); */ ; + i ++; + } + } + __e_acsl_delete_block((void *)(& y)); + __e_acsl_delete_block((void *)(& x)); + return; +} + +int main(void) +{ + int __retres; + __e_acsl_memory_init((int *)0,(char ***)0,(size_t)8); + int x = 0; + __e_acsl_store_block((void *)(& x),(size_t)4); + __e_acsl_full_init((void *)(& x)); + int *y = malloc(sizeof(int)); + __e_acsl_store_block((void *)(& y),(size_t)8); + __e_acsl_full_init((void *)(& y)); + __gen_e_acsl_f(& x,y); + __retres = 0; + __e_acsl_delete_block((void *)(& y)); + __e_acsl_delete_block((void *)(& x)); + __e_acsl_memory_clean(); + return __retres; +} + +/*@ requires \valid(y); + requires *x ≥ 0; + ensures *\old(x) ≡ \old(*x) + 1; + assigns *x; + assigns *x \from *x, x; + + behavior b1: + assumes *y ≡ 1; + ensures *\old(x) < 0; + assigns \nothing; + + behavior b2: + assumes *x ≡ 0; + ensures *\old(x) ≡ 1; + + complete behaviors b2, b1; + disjoint behaviors b1, b2; + */ +void __gen_e_acsl_f(int *x, int *y) +{ + int *__gen_e_acsl_at_2; + int __gen_e_acsl_at; + { + int __gen_e_acsl_valid; + __e_acsl_store_block((void *)(& y),(size_t)8); + __e_acsl_store_block((void *)(& x),(size_t)8); + __gen_e_acsl_valid = __e_acsl_valid((void *)y,sizeof(int),(void *)y, + (void *)(& y)); + __e_acsl_assert(__gen_e_acsl_valid,(char *)"Precondition",(char *)"f", + (char *)"\\valid(y)",12); + } + __gen_e_acsl_at_2 = x; + { + int __gen_e_acsl_valid_read; + __gen_e_acsl_valid_read = __e_acsl_valid_read((void *)y,sizeof(int), + (void *)y,(void *)(& y)); + __e_acsl_assert(__gen_e_acsl_valid_read,(char *)"RTE",(char *)"f", + (char *)"mem_access: \\valid_read(y)",17); + __gen_e_acsl_at = *y == 1; + } + f(x,y); + { + int __gen_e_acsl_implies; + if (! __gen_e_acsl_at) __gen_e_acsl_implies = 1; + else { + int __gen_e_acsl_valid_read_2; + __gen_e_acsl_valid_read_2 = __e_acsl_valid_read((void *)__gen_e_acsl_at_2, + sizeof(int), + (void *)__gen_e_acsl_at_2, + (void *)(& __gen_e_acsl_at_2)); + __e_acsl_assert(__gen_e_acsl_valid_read_2,(char *)"RTE",(char *)"f", + (char *)"mem_access: \\valid_read(__gen_e_acsl_at_2)", + 19); + __gen_e_acsl_implies = *__gen_e_acsl_at_2 < 0; + } + __e_acsl_assert(__gen_e_acsl_implies,(char *)"Postcondition",(char *)"f", + (char *)"\\old(*y == 1) ==> *\\old(x) < 0",19); + __e_acsl_delete_block((void *)(& y)); + __e_acsl_delete_block((void *)(& x)); + return; + } +} + + diff --git a/src/plugins/e-acsl/tests/temporal/oracle/t_malloc-asan.res.oracle b/src/plugins/e-acsl/tests/temporal/oracle/t_malloc-asan.res.oracle index 1adfbf4c3325a5ac415b0ba674c6c4237c8c2c29..a184f0a503377e05cd1531e6742d2b52d8c0064f 100644 --- a/src/plugins/e-acsl/tests/temporal/oracle/t_malloc-asan.res.oracle +++ b/src/plugins/e-acsl/tests/temporal/oracle/t_malloc-asan.res.oracle @@ -4,4 +4,6 @@ if there are memory-related annotations. tests/temporal/t_malloc-asan.c:31:[e-acsl] warning: E-ACSL construct `logic function application' is not yet supported. Ignoring annotation. +tests/temporal/t_malloc-asan.c:31:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. + Ignoring annotation. [e-acsl] translation done in project "e-acsl". diff --git a/src/plugins/e-acsl/tests/temporal/oracle/t_memcpy.res.oracle b/src/plugins/e-acsl/tests/temporal/oracle/t_memcpy.res.oracle index caf187356b86b329a85cb8fec3cf23af87b9f4c0..4da3a698ac4b3a1ae9c60a39bc653ea01101545d 100644 --- a/src/plugins/e-acsl/tests/temporal/oracle/t_memcpy.res.oracle +++ b/src/plugins/e-acsl/tests/temporal/oracle/t_memcpy.res.oracle @@ -11,8 +11,6 @@ FRAMAC_SHARE/libc/string.h:82:[e-acsl] warning: E-ACSL construct `assigns clause Ignoring annotation. FRAMAC_SHARE/libc/string.h:85:[e-acsl] warning: E-ACSL construct `user-defined logic type' is not yet supported. Ignoring annotation. -FRAMAC_SHARE/libc/string.h:85:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. - Ignoring annotation. FRAMAC_SHARE/libc/string.h:60:[e-acsl] warning: E-ACSL construct `trange' is not yet supported. Ignoring annotation. FRAMAC_SHARE/libc/string.h:61:[e-acsl] warning: E-ACSL construct `trange' is not yet supported. Ignoring annotation. FRAMAC_SHARE/libc/string.h:62:[e-acsl] warning: E-ACSL construct `\separated' is not yet supported. Ignoring annotation. @@ -20,6 +18,4 @@ FRAMAC_SHARE/libc/string.h:62:[e-acsl] warning: E-ACSL construct `assigns clause Ignoring annotation. FRAMAC_SHARE/libc/string.h:65:[e-acsl] warning: E-ACSL construct `logic function returning an integer' is not yet supported. Ignoring annotation. -FRAMAC_SHARE/libc/string.h:65:[e-acsl] warning: E-ACSL construct `assigns clause in behavior' is not yet supported. - Ignoring annotation. [e-acsl] translation done in project "e-acsl". diff --git a/src/plugins/e-acsl/translate.ml b/src/plugins/e-acsl/translate.ml index 7b6b7e4dd56892b218a5fbc162064d86789566a1..f2eb5dab38c2491a5cf4cfd64951ed37a11dd063 100644 --- a/src/plugins/e-acsl/translate.ml +++ b/src/plugins/e-acsl/translate.ml @@ -866,7 +866,10 @@ let term_to_exp typ t = (* ************************************************************************** *) (* [translate_*] translates a given ACSL annotation into the corresponding C - statement (if any) for runtime assertion checking *) + statement (if any) for runtime assertion checking. + + IMPORTANT: the order of translation of pre-/post-spec must be consistent with + the pushes done in [Keep_status] *) (* ************************************************************************** *) let assumes_predicate bhv = @@ -881,26 +884,14 @@ let assumes_predicate bhv = let original_project_ref = ref Project_skeleton.dummy let set_original_project p = original_project_ref := p -let must_translate ppt = - let selection = - State_selection.of_list [ Property_status.self; Options.Valid.self ] - in - Project.on ~selection - !original_project_ref - (fun ppt -> - match Property_status.get ppt with - | Property_status.Best(Property_status.True, _) -> Options.Valid.get () - | _ -> true) - ppt - -let translate_preconditions kf kinstr env behaviors = +let translate_preconditions kf env behaviors = let env = Env.set_annotation_kind env Misc.Precondition in let do_behavior env b = let assumes_pred = assumes_predicate b in List.fold_left (fun env p -> let do_it env = - if must_translate (Property.ip_of_requires kf kinstr b p) then + if Keep_status.must_translate kf Keep_status.K_Requires then let loc = p.ip_content.pred_loc in let p = Logic_const.pimplies @@ -918,24 +909,25 @@ let translate_preconditions kf kinstr env behaviors = in List.fold_left do_behavior env behaviors -let translate_postconditions kf kinstr env behaviors = +let translate_postconditions kf env behaviors = let env = Env.set_annotation_kind env Misc.Postcondition in - (* generate one guard by postcondition of each behavior *) + (* generate one guard by postcondition of each behavior *) let do_behavior env b = + let env = + handle_error + (fun env -> + (* test ordering does matter for keeping statuses consistent *) + if b.b_assigns <> WritesAny + && Keep_status.must_translate kf Keep_status.K_Assigns + then not_yet env "assigns clause in behavior"; + (* ignore b.b_extended since we never translate them *) + env) + env + in let assumes_pred = assumes_predicate b in List.fold_left - (fun env (t, p as post) -> - if must_translate (Property.ip_of_ensures kf kinstr b post) then - let env = - handle_error - (fun env -> - if b.b_assigns <> WritesAny then - not_yet env "assigns clause in behavior"; - if b.b_extended <> [] then - not_yet env "grammar extensions in behavior"; - env) - env - in + (fun env (t, p) -> + if Keep_status.must_translate kf Keep_status.K_Ensures then let do_it env = match t with | Normal -> @@ -956,57 +948,62 @@ let translate_postconditions kf kinstr env behaviors = env b.b_post_cond in - List.fold_left do_behavior env behaviors + (* fix ordering of behaviors' iterations *) + let bhvs = + List.sort (fun b1 b2 -> String.compare b1.b_name b2.b_name) behaviors + in + List.fold_left do_behavior env bhvs -let translate_pre_spec kf kinstr env spec = +let translate_pre_spec kf env spec = let unsupported f x = ignore (handle_error (fun env -> f x; env) env) in let convert_unsupported_clauses env = unsupported (Extlib.may - (fun v -> - if must_translate (Property.ip_of_decreases kf kinstr v) then - not_yet env "variant clause")) + (fun _ -> + if Keep_status.must_translate kf Keep_status.K_Decreases then + not_yet env "variant clause")) spec.spec_variant; + (* TODO: spec.spec_terminates is not part of the E-ACSL subset *) unsupported (Extlib.may - (fun t -> - if must_translate (Property.ip_of_terminates kf kinstr t) then - not_yet env "terminates clause")) + (fun _ -> + if Keep_status.must_translate kf Keep_status.K_Terminates then + not_yet env "terminates clause")) spec.spec_terminates; (match spec.spec_complete_behaviors with | [] -> () | l -> unsupported (List.iter - (fun l -> - if must_translate (Property.ip_of_complete kf kinstr ~active:[] l) - then not_yet env "complete behaviors")) + (fun _ -> + if Keep_status.must_translate kf Keep_status.K_Complete then + not_yet env "complete behaviors")) l); (match spec.spec_disjoint_behaviors with | [] -> () | l -> unsupported (List.iter - (fun l -> - if must_translate (Property.ip_of_disjoint kf kinstr ~active:[] l) - then not_yet env "disjoint behaviors")) + (fun _ -> + if Keep_status.must_translate kf Keep_status.K_Disjoint then + not_yet env "disjoint behaviors")) l); env in let env = convert_unsupported_clauses env in handle_error - (fun env -> translate_preconditions kf kinstr env spec.spec_behavior) + (fun env -> translate_preconditions kf env spec.spec_behavior) env -let translate_post_spec kf kinstr env spec = +let translate_post_spec kf env spec = handle_error - (fun env -> translate_postconditions kf kinstr env spec.spec_behavior) + (fun env -> translate_postconditions kf env spec.spec_behavior) env -let translate_pre_code_annotation kf stmt env annot = +let translate_pre_code_annotation kf env annot = let convert env = match annot.annot_content with | AAssert(l, p) -> - if must_translate (Property.ip_of_code_annot_single kf stmt annot) then + if Keep_status.must_translate kf Keep_status.K_Assert then let env = Env.set_annotation_kind env Misc.Assertion in if l <> [] then not_yet env "@[assertion applied only on some behaviors@]"; @@ -1016,9 +1013,9 @@ let translate_pre_code_annotation kf stmt env annot = | AStmtSpec(l, spec) -> if l <> [] then not_yet env "@[statement contract applied only on some behaviors@]"; - translate_pre_spec kf (Kstmt stmt) env spec ; + translate_pre_spec kf env spec ; | AInvariant(l, loop_invariant, p) -> - if must_translate (Property.ip_of_code_annot_single kf stmt annot) then + if Keep_status.must_translate kf Keep_status.K_Invariant then let env = Env.set_annotation_kind env Misc.Invariant in if l <> [] then not_yet env "@[invariant applied only on some behaviors@]"; @@ -1027,15 +1024,16 @@ let translate_pre_code_annotation kf stmt env annot = else env | AVariant _ -> - if must_translate (Property.ip_of_code_annot_single kf stmt annot) + if Keep_status.must_translate kf Keep_status.K_Variant then not_yet env "variant" else env | AAssigns _ -> - if must_translate (Property.ip_of_code_annot_single kf stmt annot) + (* TODO: it is not a precondition *) + if Keep_status.must_translate kf Keep_status.K_Assigns then not_yet env "assigns" else env | AAllocation _ -> - if must_translate (Property.ip_of_code_annot_single kf stmt annot) + if Keep_status.must_translate kf Keep_status.K_Allocation then not_yet env "allocation" else env | APragma _ -> not_yet env "pragma" @@ -1043,9 +1041,9 @@ let translate_pre_code_annotation kf stmt env annot = in handle_error convert env -let translate_post_code_annotation kf stmt env annot = +let translate_post_code_annotation kf env annot = let convert env = match annot.annot_content with - | AStmtSpec(_, spec) -> translate_post_spec kf (Kstmt stmt) env spec + | AStmtSpec(_, spec) -> translate_post_spec kf env spec | AAssert _ | AInvariant _ | AVariant _ diff --git a/src/plugins/e-acsl/translate.mli b/src/plugins/e-acsl/translate.mli index 56a484dccc2fc13ec73dc4c4a618b320720879d0..9fa04a7600d3e8095a601ef0fcd224f8efb547dc 100644 --- a/src/plugins/e-acsl/translate.mli +++ b/src/plugins/e-acsl/translate.mli @@ -26,12 +26,12 @@ open Cil_types statement (if any) for runtime assertion checking. This C statements are part of the resulting environment. *) -val translate_pre_spec: kernel_function -> kinstr -> Env.t -> funspec -> Env.t -val translate_post_spec: kernel_function -> kinstr -> Env.t -> funspec -> Env.t -val translate_pre_code_annotation: - kernel_function -> stmt -> Env.t -> code_annotation -> Env.t -val translate_post_code_annotation: - kernel_function -> stmt -> Env.t -> code_annotation -> Env.t +val translate_pre_spec: kernel_function -> Env.t -> funspec -> Env.t +val translate_post_spec: kernel_function -> Env.t -> funspec -> Env.t +val translate_pre_code_annotation: + kernel_function -> Env.t -> code_annotation -> Env.t +val translate_post_code_annotation: + kernel_function -> Env.t -> code_annotation -> Env.t val translate_named_predicate: kernel_function -> Env.t -> predicate -> Env.t diff --git a/src/plugins/e-acsl/visit.ml b/src/plugins/e-acsl/visit.ml index b8582fe2960e7529af5195f5d15b11ee09b6e87e..c475f5398ba460fc68eb60321f3d0e6640c71ca3 100644 --- a/src/plugins/e-acsl/visit.ml +++ b/src/plugins/e-acsl/visit.ml @@ -552,10 +552,7 @@ you must call function `%s' and `__e_acsl_memory_clean by yourself.@]" env in (* translate the precondition of the function *) - if Dup_functions.is_generated (Extlib.the self#current_kf) then - Project.on prj (Translate.translate_pre_spec kf Kglobal env) !funspec - else - env + Project.on prj (Translate.translate_pre_spec kf env) !funspec else env in @@ -569,10 +566,7 @@ you must call function `%s' and `__e_acsl_memory_clean by yourself.@]" Cil.visitCilCodeAnnotation (self :> Cil.cilVisitor) old_a in let env = - Project.on - prj - (Translate.translate_pre_code_annotation kf stmt env) - a + Project.on prj (Translate.translate_pre_code_annotation kf env) a in env, a :: new_annots) (Cil.get_original_stmt self#behavior stmt) @@ -619,8 +613,7 @@ you must call function `%s' and `__e_acsl_memory_clean by yourself.@]" Project.on prj (List.fold_right - (fun a env -> - Translate.translate_post_code_annotation kf stmt env a) + (fun a env -> Translate.translate_post_code_annotation kf env a) new_annots) env in @@ -640,13 +633,7 @@ you must call function `%s' and `__e_acsl_memory_clean by yourself.@]" let env = mk_post_env env in (* also handle the postcondition of the function and clear the env *) let env = - if Dup_functions.is_generated (Extlib.the self#current_kf) then - Project.on - prj - (Translate.translate_post_spec kf Kglobal env) - !funspec - else - env + Project.on prj (Translate.translate_post_spec kf env) !funspec in (* de-allocating memory previously allocating by the kf *) (* JS: should be done in the new project? *) @@ -848,8 +835,10 @@ you must call function `%s' and `__e_acsl_memory_clean by yourself.@]" initializer Misc.reset (); Literal_strings.reset (); + Keep_status.before_translation (); self#reset_env (); Translate.set_original_project (Project.current ()) + end let do_visit ?(prj=Project.current ()) generate =