From a8665b8a6958af290160d2140665484f3ce197d0 Mon Sep 17 00:00:00 2001 From: Fonenantsoa Maurica <maurica.fonenantsoa@gmail.com> Date: Mon, 1 Oct 2018 13:52:36 +0200 Subject: [PATCH] Refactor At.mk_storing_loops with Quantif.mk_for_loops. --- src/plugins/e-acsl/Makefile.in | 2 +- src/plugins/e-acsl/at_with_lscope.ml | 234 ++++------ src/plugins/e-acsl/env.ml | 51 ++- src/plugins/e-acsl/env.mli | 6 +- src/plugins/e-acsl/loops.ml | 191 +++++++- src/plugins/e-acsl/loops.mli | 30 +- src/plugins/e-acsl/lscope.ml | 4 +- src/plugins/e-acsl/lscope.mli | 3 +- src/plugins/e-acsl/quantif.ml | 235 +++------- src/plugins/e-acsl/quantif.mli | 5 +- .../tests/gmp/at_on-purely-logic-variables.c | 9 + .../at_on-purely-logic-variables.0.res.oracle | 71 ++- .../at_on-purely-logic-variables.1.res.oracle | 13 +- .../oracle/gen_at_on-purely-logic-variables.c | 417 ++++++++++++------ .../gen_at_on-purely-logic-variables2.c | 11 + src/plugins/e-acsl/translate.ml | 3 +- src/plugins/e-acsl/translate.mli | 8 +- 17 files changed, 752 insertions(+), 541 deletions(-) diff --git a/src/plugins/e-acsl/Makefile.in b/src/plugins/e-acsl/Makefile.in index adfb3eccf89..13768e6bfbc 100644 --- a/src/plugins/e-acsl/Makefile.in +++ b/src/plugins/e-acsl/Makefile.in @@ -75,12 +75,12 @@ PLUGIN_CMO:= local_config \ dup_functions \ interval \ typing \ + loops \ quantif \ at_with_lscope \ translate \ temporal \ prepare_ast \ - loops \ visit \ main diff --git a/src/plugins/e-acsl/at_with_lscope.ml b/src/plugins/e-acsl/at_with_lscope.ml index 7611d53eb17..6f01e99b709 100644 --- a/src/plugins/e-acsl/at_with_lscope.ml +++ b/src/plugins/e-acsl/at_with_lscope.ml @@ -66,20 +66,33 @@ end (* Builds the terms [t_size] and [t_shifted] from each [Lvs_quantif(tmin, lv, tmax)] from [lscope] - where [t_size = tmax - tmin + 1] (+1 because the inequalities are large - due to previous normalization) - and [t_shifted = lv - tmin] (so that we start indexing at 0) *) + where [t_size = tmax - tmin + (-1|0|1)] depending on whether the + inequalities are strict or large + and [t_shifted = lv - tmin + (-1|0)] (so that we start indexing at 0) *) let rec sizes_and_shifts_from_quantifs ~loc kf lscope sizes_and_shifts = match lscope with | [] -> sizes_and_shifts - | Lscope.Lvs_quantif(tmin, _, tmax) ::_ + | Lscope.Lvs_quantif(tmin, _, _, _, tmax) ::_ when Misc.term_has_lv_from_vi tmin || Misc.term_has_lv_from_vi tmax -> Error.not_yet "\\at with logic variable linked to C variable" - | Lscope.Lvs_quantif(tmin, lv, tmax) :: lscope' -> + | Lscope.Lvs_quantif(tmin, rel1, lv, rel2, tmax) :: lscope' -> let t_size = Logic_const.term ~loc (TBinOp(MinusA, tmax, tmin)) Linteger in - let t_size = - Logic_const.term ~loc (TBinOp(PlusA, t_size, Cil.lone ~loc ())) Linteger + let t_size = match rel1, rel2 with + | Rle, Rle -> + Logic_const.term + ~loc + (TBinOp(PlusA, t_size, Cil.lone ~loc ())) + Linteger + | Rlt, Rle | Rle, Rlt -> + t_size + | Rlt, Rlt -> + Logic_const.term + ~loc + (TBinOp(MinusA, t_size, Cil.lone ~loc ())) + Linteger + | _ -> + Options.fatal "Unexpected comparison operator" in let i = Interval.infer t_size in (* The EXACT amount of memory that is needed can be known at runtime. This @@ -100,17 +113,23 @@ let rec sizes_and_shifts_from_quantifs ~loc kf lscope sizes_and_shifts = needed, the number of reads/writes into it is the same in both cases. Conclusion: over-approximate [t_size] *) let t_size = match Ival.min_and_max i with - | _, Some max -> - Logic_const.tint ~loc max - | _, None -> - Error.not_yet - "\\at on purely logic variables and with quantifier that uses \ - too complex bound (E-ACSL cannot infer a finite upper bound to it)" + | _, Some max -> + Logic_const.tint ~loc max + | _, None -> + Error.not_yet + "\\at on purely logic variables and with quantifier that uses \ + too complex bound (E-ACSL cannot infer a finite upper bound to it)" in (* Index *) let t_lv = Logic_const.tvar ~loc lv in - let t_shifted = - Logic_const.term ~loc (TBinOp(MinusA, t_lv, tmin)) Linteger + let t_shifted = match rel1 with + | Rle -> + Logic_const.term ~loc (TBinOp(MinusA, t_lv, tmin)) Linteger + | Rlt -> + let t = Logic_const.term ~loc (TBinOp(MinusA, t_lv, tmin)) Linteger in + Logic_const.term ~loc (TBinOp(MinusA, t, Cil.lone ~loc())) Linteger + | _ -> + Options.fatal "Unexpected comparison operator" in (* Returning *) let sizes_and_shifts = (t_size, t_shifted) :: sizes_and_shifts in @@ -138,13 +157,6 @@ let size_from_sizes_and_shifts ~loc = function size sizes_and_shifts -let append_block_of_env_to_block env block = - let block_stmt = Cil.mkStmt ~valid_sid:true (Block block) in - let block, env = - Env.pop_and_get env block_stmt ~global_clear:false Env.After - in - block, env - (* Build the left-value corresponding to [*(at + index)]. *) let lval_at_index ~loc kf env (e_at, vi_at, t_index) = Typing.type_term ~use_gmp_opt:false ~ctx:Typing.c_int t_index; @@ -157,129 +169,6 @@ let lval_at_index ~loc kf env (e_at, vi_at, t_index) = let lval_at_index = Mem e_addr, NoOffset in lval_at_index, env -(* [mk_storing_loops] creates the nested loops that are used to store the - different possible values of [pot]. - These loops are similar to those generated by [Quantif], with the difference - that the aim of the innermost block is to store values, - not to check the validity of some (quantified) predicate. *) -let rec mk_storing_loops ~loc kf env lscope (e_at, vi_at, t_index) pot = - let term_to_exp = !term_to_exp_ref in - let named_predicate_to_exp = !predicate_to_exp_ref in - match lscope, pot with - | [], Misc.PoT_pred p -> - let env = Env.push env in - let lval, env = lval_at_index ~loc kf env (e_at, vi_at, t_index) in - let e, env = named_predicate_to_exp kf env p in - let storing_stmt = - Cil.mkStmtOneInstr ~valid_sid:true (Set(lval, e, loc)) - in - let block, env = - Env.pop_and_get env storing_stmt ~global_clear:false Env.After - in - block, env - | [], Misc.PoT_term t -> - begin match Typing.get_integer_ty t with - | Typing.C_type _ | Typing.Other -> - let env = Env.push env in - let lval, env = lval_at_index ~loc kf env (e_at, vi_at, t_index) in - let e, env = term_to_exp kf env t in - let storing_stmt = - Cil.mkStmtOneInstr ~valid_sid:true (Set(lval, e, loc)) - in - let block, env = - Env.pop_and_get env storing_stmt ~global_clear:false Env.After - in - block, env - | Typing.Gmp -> - Error.not_yet "\\at on purely logic variables and over gmp type" - end - | Lscope.Lvs_quantif(tmin, lv, tmax) :: lscope', pot -> - (* TODO: a refactor with [Quantif] may be possible for this case *) - let vi_of_lv_old = Env.Logic_binding.get env lv in - let env = Env.push env in - let vi_of_lv, _, env = - (* We need to redeclare the lv thus new varinfo needed *) - Env.Logic_binding.add ~ty:vi_of_lv_old.vtype env lv - in - let t_lv = Logic_const.tvar ~loc lv in - (* Guard *) - let guard = - Logic_const.term ~loc (TBinOp(Le, t_lv, tmax)) (Ctype Cil.intType) - in - Typing.type_term ~use_gmp_opt:false ~ctx:Typing.c_int guard; - let guard_exp, env = term_to_exp kf env guard in - (* Break *) - let break_stmt = Cil.mkStmt ~valid_sid:true (Break guard_exp.eloc) in - (* Inner loop *) - let loop', env = - mk_storing_loops ~loc kf env lscope' (e_at, vi_at, t_index) pot - in - let loop' = Cil.mkStmt ~valid_sid:true (Block loop') in - (* Loop counter *) - let plus_one_term = Logic_const.term - ~loc - (TBinOp(PlusA, t_lv, Cil.lone ~loc ())) - Linteger - in - Typing.type_term ~use_gmp_opt:true plus_one_term; - let plus_one_exp, env = term_to_exp kf env plus_one_term in - let plus_one_stmt = match Typing.get_integer_ty plus_one_term with - | Typing.C_type _ | Typing.Gmp -> - Gmpz.init_set ~loc (Cil.var vi_of_lv) (Cil.evar vi_of_lv) plus_one_exp - | Typing.Other -> - assert false - in - (* If guard is satisfiable then inner loop, else break *) - let if_stmt = Cil.mkStmt - ~valid_sid:true - (If(guard_exp, - Cil.mkBlock [ loop'; plus_one_stmt ], - Cil.mkBlock [ break_stmt ], - guard_exp.eloc)) - in - let loop = Cil.mkStmt - ~valid_sid:true - (Loop ([], - Cil.mkBlock [ if_stmt ], - loc, - None, - Some break_stmt)) - in - (* Init lv *) - let tmin_exp, env = term_to_exp kf env tmin in - let set_tmin = match Typing.get_integer_ty plus_one_term with - | Typing.C_type _ | Typing.Gmp -> - Gmpz.init_set ~loc (Cil.var vi_of_lv) (Cil.evar vi_of_lv) tmin_exp - | Typing.Other -> - assert false - in - (* The whole block *) - let block = Cil.mkBlock [set_tmin; loop] in - let b, env = append_block_of_env_to_block env block in - let env = Env.Logic_binding.set env lv vi_of_lv_old in - b, env - | Lscope.Lvs_let(lv, t) :: lscope', pot -> - let vi_of_lv_old = Env.Logic_binding.get env lv in - let env = Env.push env in - let vi_of_lv, exp_of_lv, env = - (* We need to redeclare the lv thus new varinfo needed *) - Env.Logic_binding.add ~ty:vi_of_lv_old.vtype env lv - in - let e, env = term_to_exp kf env t in - let let_stmt = Gmpz.init_set ~loc (Cil.var vi_of_lv) exp_of_lv e in - let block, env = - mk_storing_loops ~loc kf env lscope' (e_at, vi_at, t_index) pot - in - (* The whole block *) - block.bstmts <- let_stmt :: block.bstmts; - let b, env = append_block_of_env_to_block env block in - let env = Env.Logic_binding.set env lv vi_of_lv_old in - b, env - | Lscope.Lvs_formal _ :: _, _ -> - Error.not_yet "\\at using formal variable of a logic function" - | Lscope.Lvs_global _ :: _ , _-> - Error.not_yet "\\at using global logic variable" - (* Associate to each possible tuple of quantifiers a unique index from the set {n | 0 <= n < n_max}. That index will serve to identify the memory location where the evaluation @@ -390,15 +279,60 @@ let to_exp ~loc kf env pot label = in (* Index *) let t_index = index_from_sizes_and_shifts ~loc sizes_and_shifts in + (* Innermost block *) + let mk_innermost_block env = + let term_to_exp = !term_to_exp_ref in + let named_predicate_to_exp = !predicate_to_exp_ref in + match pot with + | Misc.PoT_pred p -> + let env = Env.push env in + let lval, env = lval_at_index ~loc kf env (e_at, vi_at, t_index) in + let e, env = named_predicate_to_exp kf env p in + let e = Cil.constFold false e in + let storing_stmt = + Cil.mkStmtOneInstr ~valid_sid:true (Set(lval, e, loc)) + in + let block, env = + Env.pop_and_get env storing_stmt ~global_clear:false Env.After + in + (* We CANNOT return [block.bstmts] because it does NOT contain + variable declarations. *) + [ Cil.mkStmt ~valid_sid:true (Block block) ], env + | Misc.PoT_term t -> + begin match Typing.get_integer_ty t with + | Typing.C_type _ | Typing.Other -> + let env = Env.push env in + let lval, env = lval_at_index ~loc kf env (e_at, vi_at, t_index) in + let e, env = term_to_exp kf env t in + let e = Cil.constFold false e in + let storing_stmt = + Cil.mkStmtOneInstr ~valid_sid:true (Set(lval, e, loc)) + in + let block, env = + Env.pop_and_get env storing_stmt ~global_clear:false Env.After + in + (* We CANNOT return [block.bstmts] because it does NOT contain + variable declarations. *) + [ Cil.mkStmt ~valid_sid:true (Block block) ], env + | Typing.Gmp -> + Error.not_yet "\\at on purely logic variables and over gmp type" + end + in (* Storing loops *) let lscope_vars = Lscope.get_all (Env.Logic_scope.get env) in - let storing_loops, env = - mk_storing_loops ~loc kf env lscope_vars (e_at, vi_at, t_index) pot - (* [t_index] MUST NOT be translated here because the logic bindings - will differ once inside [mk_storing_loops] *) + let env = Env.push env in + let storing_loops_stmts, env = + Loops.mk_nested_loops ~loc mk_innermost_block kf env lscope_vars + in + let storing_loops_block = Cil.mkBlock storing_loops_stmts in + let storing_loops_block, env = Env.pop_and_get + env + (Cil.mkStmt ~valid_sid:true (Block storing_loops_block)) + ~global_clear:false + Env.After in (* Put at label *) - let env = put_block_at_label env storing_loops label in + let env = put_block_at_label env storing_loops_block label in (* Returning *) let lval_at_index, env = lval_at_index ~loc kf env (e_at, vi_at, t_index) in let e = Cil.new_exp ~loc (Lval lval_at_index) in diff --git a/src/plugins/e-acsl/env.ml b/src/plugins/e-acsl/env.ml index 4c1114d2261..af52b7caf17 100644 --- a/src/plugins/e-acsl/env.ml +++ b/src/plugins/e-acsl/env.ml @@ -61,7 +61,8 @@ type t = global_mpz_tbl: mpz_tbl; env_stack: local_env list; init_env: local_env; - var_mapping: Varinfo.t Logic_var.Map.t; (* bind logic var to C var *) + var_mapping: (Varinfo.t list) Logic_var.Map.t; + (* records of C bindings for logic vars *) loop_invariants: predicate list list; (* list of loop invariants for each currently visited loops *) cpt: int; (* counter used when generating variables *) } @@ -286,32 +287,50 @@ module Logic_binding = struct | Ctype ty -> ty | Linteger -> Gmpz.t () | Ltype _ as ty when Logic_const.is_boolean_type ty -> Cil.charType - | Ltype _ | Lvar _ | Lreal | Larrow _ as lty -> - let msg = + | Ltype _ | Lvar _ | Lreal | Larrow _ as lty -> + let msg = Format.asprintf "logic variable of type %a" Logic_type.pretty lty in Error.not_yet msg in - let v, e, env = - new_var - ~loc:Location.unknown env ~name:logic_v.lv_name None ty (fun _ _ -> []) + let v, e, env = new_var + ~loc:Location.unknown + env + ~name:logic_v.lv_name + None + ty + (fun _ _ -> []) + in + let bindings = + try v :: (Logic_var.Map.find logic_v env.var_mapping) + with Not_found -> [ v ] in v, - e, - { env with var_mapping = Logic_var.Map.add logic_v v env.var_mapping } + e, + { env with var_mapping = + Logic_var.Map.add logic_v bindings env.var_mapping } - let get env logic_v = - try Logic_var.Map.find logic_v env.var_mapping + let get env logic_v = + try + match Logic_var.Map.find logic_v env.var_mapping with + | [] -> assert false + | vi :: _ -> vi with Not_found -> assert false - let set env lv vi = - { env with var_mapping = Logic_var.Map.add lv vi env.var_mapping } - - let remove env v = + let remove env v = let map = env.var_mapping in - assert (Logic_var.Map.mem v map); - { env with var_mapping = Logic_var.Map.remove v map } + let bindings = + try Logic_var.Map.find v env.var_mapping + with Not_found -> assert false + in + match bindings with + | [] -> + assert false + | [ _ ] -> + { env with var_mapping = Logic_var.Map.remove v map } + | _ :: bindings -> + { env with var_mapping = Logic_var.Map.add v bindings env.var_mapping } end diff --git a/src/plugins/e-acsl/env.mli b/src/plugins/e-acsl/env.mli index aa9aeda495a..b56fe807cd8 100644 --- a/src/plugins/e-acsl/env.mli +++ b/src/plugins/e-acsl/env.mli @@ -66,9 +66,13 @@ val new_var_and_mpz_init: module Logic_binding: sig val add: ?ty:typ -> t -> logic_var -> varinfo * exp * t + (* Add a new C binding to the list of bindings for the logic variable. *) + val get: t -> logic_var -> varinfo - val set: t -> logic_var -> varinfo -> t + (* Return the latest C binding. *) + val remove: t -> logic_var -> t + (* Remove the latest C binding. *) end val add_assert: t -> stmt -> predicate -> unit diff --git a/src/plugins/e-acsl/loops.ml b/src/plugins/e-acsl/loops.ml index 3997c2c9ef3..9f982de071a 100644 --- a/src/plugins/e-acsl/loops.ml +++ b/src/plugins/e-acsl/loops.ml @@ -20,27 +20,44 @@ (* *) (**************************************************************************) +open Cil open Cil_types +(**************************************************************************) +(********************** Forward references ********************************) +(**************************************************************************) + +let translate_named_predicate_ref + : (kernel_function -> Env.t -> predicate -> Env.t) ref + = Extlib.mk_fun "translate_named_predicate_ref" + +let term_to_exp_ref + : (kernel_function -> Env.t -> term -> exp * Env.t) ref + = Extlib.mk_fun "term_to_exp_ref" + +(**************************************************************************) +(************************* Loop invariants ********************************) +(**************************************************************************) + module Loop_invariants_actions = Hook.Make(struct end) let apply_after_transformation prj = Project.on prj Loop_invariants_actions.apply () -let mv_invariants env ~old stmt = +let mv_invariants env ~old stmt = Options.feedback ~current:true ~level:3 "keep loop invariants attached to its loop"; match Env.current_kf env with | None -> assert false | Some kf -> - let filter _ ca = match ca.annot_content with + let filter _ ca = match ca.annot_content with | AInvariant(_, b, _) -> b | _ -> false in let l = Annotations.code_annot_emitter ~filter stmt in if l != [] then Loop_invariants_actions.extend - (fun () -> + (fun () -> List.iter (fun (ca, e) -> Annotations.remove_code_annot e ~kf old ca; @@ -48,21 +65,22 @@ let mv_invariants env ~old stmt = l) let preserve_invariant prj env kf stmt = match stmt.skind with - | Loop(_, ({ bstmts = stmts } as blk), loc, cont, break) -> + | Loop(_, ({ bstmts = stmts } as blk), loc, cont, break) -> let rec handle_invariants (stmts, env, _ as acc) = function - | [] -> + | [] -> (* empty loop body: no need to verify the invariant twice *) acc - | [ last ] -> + | [ last ] -> let invariants, env = Env.pop_loop env in let env = Env.push env in - let env = + let env = + let translate_named_predicate = !translate_named_predicate_ref in Project.on prj - (List.fold_left (Translate.translate_named_predicate kf) env) - invariants + (List.fold_left (translate_named_predicate kf) env) + invariants in - let blk, env = + let blk, env = Env.pop_and_get env last ~global_clear:false Env.Before in Misc.mk_block prj last blk :: stmts, env, invariants != [] @@ -71,11 +89,160 @@ let preserve_invariant prj env kf stmt = match stmt.skind with let env = Env.set_annotation_kind env Misc.Invariant in let stmts, env, has_loop = handle_invariants ([], env, false) stmts in let new_blk = { blk with bstmts = List.rev stmts } in - { stmt with skind = Loop([], new_blk, loc, cont, break) }, - env, + { stmt with skind = Loop([], new_blk, loc, cont, break) }, + env, has_loop | _ -> stmt, env, false +(**************************************************************************) +(**************************** Nested loops ********************************) +(**************************************************************************) + +let rec mk_nested_loops ~loc mk_innermost_block kf env lscope_vars = + let term_to_exp = !term_to_exp_ref in + match lscope_vars with + | [] -> + mk_innermost_block env + | Lscope.Lvs_quantif(t1, rel1, logic_x, rel2, t2) :: lscope_vars' -> + let ctx = + let ty1 = Typing.get_integer_ty t1 in + let ty2 = Typing.get_integer_ty t2 in + Typing.join ty1 ty2 + in + let t_plus_one ?ty t = + (* whenever provided, [ty] is known to be the type of the result *) + let tone = Cil.lone ~loc () in + let res = Logic_const.term ~loc (TBinOp(PlusA, t, tone)) Linteger in + Extlib.may + (fun ty -> + Typing.unsafe_set tone ~ctx:ty ctx; + Typing.unsafe_set t ~ctx:ty ctx; + Typing.unsafe_set res ty) + ty; + res + in + let t1 = match rel1 with + | Rlt -> + let t = t_plus_one t1 in + Typing.type_term ~use_gmp_opt:false ~ctx t; + t + | Rle -> + t1 + | Rgt | Rge | Req | Rneq -> + assert false + in + let t2_one, bop2 = match rel2 with + | Rlt -> + t2, Lt + | Rle -> + (* we increment the loop counter one more time (at the end of the + loop). Thus to prevent overflow, check the type of [t2+1] + instead of [t2]. *) + t_plus_one t2, Le + | Rgt | Rge | Req | Rneq -> + assert false + in + Typing.type_term ~use_gmp_opt:false ~ctx t2_one; + let ctx_one = + let ty1 = Typing.get_integer_ty t1 in + let ty2 = Typing.get_integer_ty t2_one in + Typing.join ty1 ty2 + in + let ty = + try Typing.typ_of_integer_ty ctx_one + with Typing.Not_an_integer -> assert false + in + (* loop counter corresponding to the quantified variable *) + let var_x, x, env = Env.Logic_binding.add ~ty env logic_x in + let lv_x = var var_x in + let env = match ctx_one with + | Typing.C_type _ -> env + | Typing.Gmp -> Env.add_stmt env (Gmpz.init ~loc x) + | Typing.Other -> assert false + in + (* build the inner loops and loop body *) + let body, env = + mk_nested_loops ~loc mk_innermost_block kf env lscope_vars' + in + (* initialize the loop counter to [t1] *) + let e1, env = term_to_exp kf (Env.push env) t1 in + let init_blk, env = Env.pop_and_get + env + (Gmpz.affect ~loc:e1.eloc lv_x x e1) + ~global_clear:false + Env.Middle + in + (* generate the guard [x bop t2] *) + let stmts_block b = [ mkStmt ~valid_sid:true (Block b) ] in + let tlv = Logic_const.tvar ~loc logic_x in + let guard = + (* must copy [t2] to force being typed again *) + Logic_const.term ~loc + (TBinOp(bop2, tlv, { t2 with term_node = t2.term_node } )) Linteger + in + Typing.type_term ~use_gmp_opt:false ~ctx:Typing.c_int guard; + let guard_exp, env = term_to_exp kf (Env.push env) guard in + let break_stmt = mkStmt ~valid_sid:true (Break guard_exp.eloc) in + let guard_blk, env = Env.pop_and_get + env + (mkStmt + ~valid_sid:true + (If( + guard_exp, + mkBlock [ mkEmptyStmt ~loc () ], + mkBlock [ break_stmt ], + guard_exp.eloc))) + ~global_clear:false + Env.Middle + in + let guard = stmts_block guard_blk in + (* increment the loop counter [x++]; + previous typing ensures that [x++] fits type [ty] *) + (* TODO: should check that it does not overflow in the case of the type + of the loop variable is __declared__ too small. *) + let tlv_one = t_plus_one ~ty:ctx_one tlv in + let incr, env = term_to_exp kf (Env.push env) tlv_one in + let next_blk, env = Env.pop_and_get + env + (Gmpz.affect ~loc:incr.eloc lv_x x incr) + ~global_clear:false + Env.Middle + in + (* remove logic binding now that the block is constructed *) + let env = Env.Logic_binding.remove env logic_x in + (* generate the whole loop *) + let start = stmts_block init_blk in + let next = stmts_block next_blk in + let stmt = mkStmt + ~valid_sid:true + (Loop( + [], + mkBlock (guard @ body @ next), + loc, + None, + Some break_stmt)) + in + start @ [ stmt ], env + | Lscope.Lvs_let(lv, t) :: lscope_vars' -> + let ty = Typing.get_typ t in + let vi_of_lv, exp_of_lv, env = Env.Logic_binding.add ~ty env lv in + let e, env = term_to_exp kf env t in + let let_stmt = Gmpz.init_set ~loc (Cil.var vi_of_lv) exp_of_lv e in + let stmts, env = + mk_nested_loops ~loc mk_innermost_block kf env lscope_vars' + in + (* remove logic binding now that the block is constructed *) + let env = Env.Logic_binding.remove env lv in + (* return *) + let_stmt :: stmts, env + | Lscope.Lvs_formal _ :: _ -> + Error.not_yet + "creating nested loops from formal variable of a logic function" + | Lscope.Lvs_global _ :: _ -> + Error.not_yet + "creating nested loops from global logic variable" + + (* Local Variables: compile-command: "make" diff --git a/src/plugins/e-acsl/loops.mli b/src/plugins/e-acsl/loops.mli index ba56d942004..ba113cea4db 100644 --- a/src/plugins/e-acsl/loops.mli +++ b/src/plugins/e-acsl/loops.mli @@ -24,19 +24,47 @@ open Cil_types +(**************************************************************************) +(************************* Loop invariants ********************************) +(**************************************************************************) + val apply_after_transformation: Project.t -> unit val mv_invariants: Env.t -> old:stmt -> stmt -> unit (** Transfer the loop invariants from the [old] loop to the new one. Both statements must be loops. *) -val preserve_invariant: +val preserve_invariant: Project.t -> Env.t -> Kernel_function.t -> stmt -> stmt * Env.t * bool (** modify the given stmt loop to insert the code which preserves its loop invarariants. Also return the modify environment and a boolean which indicates whether the annotations corresponding to the loop invariant must be moved from the new statement to the old one. *) +(**************************************************************************) +(**************************** Nested loops ********************************) +(**************************************************************************) + +val mk_nested_loops: + loc:location -> (Env.t -> stmt list * Env.t) -> kernel_function -> Env.t -> + Lscope.lscope_var list -> stmt list * Env.t +(** [mk_nested_loops ~loc mk_innermost_block kf env lvars] creates nested + loops (with the proper statements for the initializing the loop counters) + from the list of logic variables [lvars]. Quantified variables create + loops while let-bindings simply create new variables. + The [mk_innermost_block] closure creates the statements of the innermost + block. *) + +(**************************************************************************) +(********************** Forward references ********************************) +(**************************************************************************) + +val translate_named_predicate_ref: + (kernel_function -> Env.t -> predicate -> Env.t) ref + +val term_to_exp_ref: + (kernel_function -> Env.t -> term -> exp * Env.t) ref + (* Local Variables: compile-command: "make" diff --git a/src/plugins/e-acsl/lscope.ml b/src/plugins/e-acsl/lscope.ml index 805032015e9..a14a42fa1c9 100644 --- a/src/plugins/e-acsl/lscope.ml +++ b/src/plugins/e-acsl/lscope.ml @@ -24,7 +24,7 @@ open Cil_types type lscope_var = | Lvs_let of logic_var * term - | Lvs_quantif of term * logic_var * term + | Lvs_quantif of term * relation * logic_var * relation * term | Lvs_formal of logic_var * logic_info | Lvs_global of logic_var * term @@ -41,7 +41,7 @@ let get_all t = List.rev t let exists lv t = let is_lv = function - | Lvs_let(lv', _) | Lvs_quantif(_, lv', _) | Lvs_formal(lv', _) + | Lvs_let(lv', _) | Lvs_quantif(_, _, lv', _, _) | Lvs_formal(lv', _) | Lvs_global(lv', _) -> Cil_datatype.Logic_var.equal lv lv' in diff --git a/src/plugins/e-acsl/lscope.mli b/src/plugins/e-acsl/lscope.mli index 90f84997432..dbc8a2560f3 100644 --- a/src/plugins/e-acsl/lscope.mli +++ b/src/plugins/e-acsl/lscope.mli @@ -28,7 +28,8 @@ open Cil_types type lscope_var = | Lvs_let of logic_var * term (* the expression to which the lv is binded *) - | Lvs_quantif of term (* min *) * logic_var * term (* max *) + | Lvs_quantif of term * relation * logic_var * relation * term + (* Take good note *) | Lvs_formal of logic_var * logic_info (* the logic definition *) | Lvs_global of logic_var * term (* same as Lvs_let *) diff --git a/src/plugins/e-acsl/quantif.ml b/src/plugins/e-acsl/quantif.ml index 223c6b7da99..c0910b7eda7 100644 --- a/src/plugins/e-acsl/quantif.ml +++ b/src/plugins/e-acsl/quantif.ml @@ -25,12 +25,8 @@ open Cil open Cil_datatype let predicate_to_exp_ref - : (kernel_function -> Env.t -> predicate -> exp * Env.t) ref - = Extlib.mk_fun "named_predicate_to_exp_ref" - -let term_to_exp_ref - : (kernel_function -> Env.t -> term -> exp * Env.t) ref - = Extlib.mk_fun "term_to_exp_ref" + : (kernel_function -> Env.t -> predicate -> exp * Env.t) ref + = Extlib.mk_fun "named_predicate_to_exp_ref" let compute_quantif_guards quantif bounded_vars hyps = let error msg pp x = @@ -92,13 +88,13 @@ let compute_quantif_guards quantif bounded_vars hyps = (match vars with | [] -> () | _ :: _ -> - let msg = + let msg = Format.asprintf - "@[unguarded variable%s %tin quantification@ %a@]" - (if List.length vars = 1 then "" else "s") - (fun fmt -> + "@[unguarded variable%s %tin quantification@ %a@]" + (if List.length vars = 1 then "" else "s") + (fun fmt -> List.iter - (fun v -> Format.fprintf fmt "@[%a @]" Printer.pp_logic_var v) + (fun v -> Format.fprintf fmt "@[%a @]" Printer.pp_logic_var v) vars) Printer.pp_predicate quantif in @@ -107,49 +103,31 @@ let compute_quantif_guards quantif bounded_vars hyps = let () = Typing.compute_quantif_guards_ref := compute_quantif_guards -module Label_ids = +module Label_ids = State_builder.Counter(struct let name = "E_ACSL.Label_ids" end) let convert kf env loc is_forall p bounded_vars hyps goal = - (* part depending on the kind of quantifications + (* part depending on the kind of quantifications (either universal or existential) *) - let init_val, found_val, mk_guard = + let init_val, found_val, mk_guard = let z = zero ~loc in let o = one ~loc in - if is_forall then o, z, (fun x -> x) + if is_forall then o, z, (fun x -> x) else z, o, (fun e -> new_exp ~loc:e.eloc (UnOp(LNot, e, intType))) in - let named_predicate_to_exp = !predicate_to_exp_ref in - let term_to_exp = !term_to_exp_ref in (* universal quantification over integers (or a subtype of integer) *) let guards = compute_quantif_guards p bounded_vars hyps in - (* Update logic scope *) - let env = List.fold_left - (fun env (t1, rel1, lv, rel2, t2) -> - (* The following normalization is done here: - all the inequalities are large *) - let tone = Cil.lone ~loc () in - let t1 = match rel1 with - | Rle -> t1 - | Rlt -> Logic_const.term - ~loc - (TBinOp(PlusA, t1, tone)) - Linteger - | Rgt | Rge | Req | Rneq -> assert false - in - let t2 = match rel2 with - | Rle -> t2 - | Rlt -> Logic_const.term - ~loc - (TBinOp(MinusA, t2, tone)) - Linteger - | Rgt | Rge | Req | Rneq -> assert false - in - let lvs = Lscope.Lvs_quantif(t1, lv, t2) in - Env.Logic_scope.extend env lvs) - env + (* transform [guards] into [lscope_var list], + and update logic scope in the process *) + let env_ref = ref env in + let lvs_guards = List.map + (fun (t1, rel1, lv, rel2, t2) -> + let lvs = Lscope.Lvs_quantif(t1, rel1, lv, rel2, t2) in + env_ref := Env.Logic_scope.extend !env_ref lvs; + lvs) guards in + let env = !env_ref in let var_res, res, env = (* variable storing the result of the quantifier *) let name = if is_forall then "forall" else "exists" in @@ -160,149 +138,39 @@ let convert kf env loc is_forall p bounded_vars hyps goal = None intType (fun v _ -> - let lv = var v in - [ mkStmtOneInstr ~valid_sid:true (Set(lv, init_val, loc)) ]) + let lv = var v in + [ mkStmtOneInstr ~valid_sid:true (Set(lv, init_val, loc)) ]) in let end_loop_ref = ref dummyStmt in - let rec mk_for_loop env = function - | [] -> - (* innermost loop body: store the result in [res] and go out according - to evaluation of the goal *) - let test, env = named_predicate_to_exp kf (Env.push env) goal in - let then_block = mkBlock [ mkEmptyStmt ~loc () ] in - let else_block = - (* use a 'goto', not a simple 'break' in order to handle 'forall' with - multiple binders (leading to imbricated loops) *) - mkBlock - [ mkStmtOneInstr - ~valid_sid:true (Set(var var_res, found_val, loc)); - mkStmt ~valid_sid:true (Goto(end_loop_ref, loc)) ] - in - let blk, env = - Env.pop_and_get - env - (mkStmt ~valid_sid:true - (If(mk_guard test, then_block, else_block, loc))) - ~global_clear:false - Env.After - in - let blk = Cil.flatten_transient_sub_blocks blk in - [ mkStmt ~valid_sid:true (Block blk) ], env - | (t1, rel1, logic_x, rel2, t2) :: tl -> - let ctx = - let ty1 = Typing.get_integer_ty t1 in - let ty2 = Typing.get_integer_ty t2 in - Typing.join ty1 ty2 - in - let t_plus_one ?ty t = - (* whenever provided, [ty] is known to be the type of the result *) - let tone = Cil.lone ~loc () in - let res = Logic_const.term ~loc (TBinOp(PlusA, t, tone)) Linteger in - Extlib.may - (fun ty -> - Typing.unsafe_set tone ~ctx:ty ctx; - Typing.unsafe_set t ~ctx:ty ctx; - Typing.unsafe_set res ty) - ty; - res - in - let t1 = match rel1 with - | Rlt -> - let t = t_plus_one t1 in - Typing.type_term ~use_gmp_opt:false ~ctx t; - t - | Rle -> t1 - | Rgt | Rge | Req | Rneq -> assert false - in - let t2_one, bop2 = match rel2 with - | Rlt -> t2, Lt - | Rle -> - (* we increment the loop counter one more time (at the end of the - loop). Thus to prevent overflow, check the type of [t2+1] - instead of [t2]. *) - t_plus_one t2, Le - | Rgt | Rge | Req | Rneq -> assert false - in - Typing.type_term ~use_gmp_opt:false ~ctx t2_one; - let ctx_one = - let ty1 = Typing.get_integer_ty t1 in - let ty2 = Typing.get_integer_ty t2_one in - Typing.join ty1 ty2 - in - let ty = - try Typing.typ_of_integer_ty ctx_one - with Typing.Not_an_integer -> assert false - in - (* loop counter corresponding to the quantified variable *) - let var_x, x, env = Env.Logic_binding.add ~ty env logic_x in - let lv_x = var var_x in - let env = match ctx_one with - | Typing.C_type _ -> env - | Typing.Gmp -> Env.add_stmt env (Gmpz.init ~loc x) - | Typing.Other -> assert false - in - (* build the inner loops and loop body *) - let body, env = mk_for_loop env tl in - (* initialize the loop counter to [t1] *) - let e1, env = term_to_exp kf (Env.push env) t1 in - let init_blk, env = - Env.pop_and_get - env - (Gmpz.affect ~loc:e1.eloc lv_x x e1) - ~global_clear:false - Env.Middle - in - (* generate the guard [x bop t2] *) - let stmts_block b = [ mkStmt ~valid_sid:true (Block b) ] in - let tlv = Logic_const.tvar ~loc logic_x in - let guard = - (* must copy [t2] to force being typed again *) - Logic_const.term ~loc - (TBinOp(bop2, tlv, { t2 with term_node = t2.term_node } )) Linteger - in - Typing.type_term ~use_gmp_opt:false ~ctx:Typing.c_int guard; - let guard_exp, env = term_to_exp kf (Env.push env) guard in - let break_stmt = mkStmt ~valid_sid:true (Break guard_exp.eloc) in - let guard_blk, env = - Env.pop_and_get - env - (mkStmt ~valid_sid:true - (If(guard_exp, - mkBlock [ mkEmptyStmt ~loc () ], - mkBlock [ break_stmt ], - guard_exp.eloc))) - ~global_clear:false - Env.Middle - in - let guard = stmts_block guard_blk in - (* increment the loop counter [x++]; - previous typing ensures that [x++] fits type [ty] *) - (* TODO: should check that it does not overflow in the case of the type - of the loop variable is __declared__ too small. *) - let tlv_one = t_plus_one ~ty:ctx_one tlv in - let incr, env = term_to_exp kf (Env.push env) tlv_one in - let next_blk, env = - Env.pop_and_get - env - (Gmpz.affect ~loc:incr.eloc lv_x x incr) - ~global_clear:false - Env.Middle - in - (* generate the whole loop *) - let start = stmts_block init_blk in - let next = stmts_block next_blk in - start @ - [ mkStmt ~valid_sid:true - (Loop ([], - mkBlock (guard @ body @ next), - loc, - None, - Some break_stmt)) ], + (* innermost block *) + let mk_innermost_block env = + (* innermost loop body: store the result in [res] and go out according + to evaluation of the goal *) + let named_predicate_to_exp = !predicate_to_exp_ref in + let test, env = named_predicate_to_exp kf (Env.push env) goal in + let then_block = mkBlock [ mkEmptyStmt ~loc () ] in + let else_block = + (* use a 'goto', not a simple 'break' in order to handle 'forall' with + multiple binders (leading to imbricated loops) *) + mkBlock + [ mkStmtOneInstr ~valid_sid:true (Set(var var_res, found_val, loc)); + mkStmt ~valid_sid:true (Goto(end_loop_ref, loc)) ] + in + let blk, env = Env.pop_and_get env + (mkStmt ~valid_sid:true + (If(mk_guard test, then_block, else_block, loc))) + ~global_clear:false + Env.After + in + let blk = Cil.flatten_transient_sub_blocks blk in + [ mkStmt ~valid_sid:true (Block blk) ], env + in + let stmts, env = + Loops.mk_nested_loops ~loc mk_innermost_block kf env lvs_guards in - let stmts, env = mk_for_loop env guards in - let env = - Env.add_stmt env (mkStmt ~valid_sid:true (Block (mkBlock stmts))) + let env = + Env.add_stmt env (mkStmt ~valid_sid:true (Block (mkBlock stmts))) in (* where to jump to go out of the loop *) let end_loop = mkEmptyStmt ~loc () in @@ -311,16 +179,15 @@ let convert kf env loc is_forall p bounded_vars hyps goal = end_loop.labels <- label :: end_loop.labels; end_loop_ref := end_loop; let env = Env.add_stmt env end_loop in - let env = List.fold_left Env.Logic_binding.remove env bounded_vars in res, env let quantif_to_exp kf env p = let loc = p.pred_loc in match p.pred_content with - | Pforall(bounded_vars, { pred_content = Pimplies(hyps, goal) }) -> + | Pforall(bounded_vars, { pred_content = Pimplies(hyps, goal) }) -> convert kf env loc true p bounded_vars hyps goal | Pforall _ -> Error.not_yet "unguarded \\forall quantification" - | Pexists(bounded_vars, { pred_content = Pand(hyps, goal) }) -> + | Pexists(bounded_vars, { pred_content = Pand(hyps, goal) }) -> convert kf env loc false p bounded_vars hyps goal | Pexists _ -> Error.not_yet "unguarded \\exists quantification" | _ -> assert false diff --git a/src/plugins/e-acsl/quantif.mli b/src/plugins/e-acsl/quantif.mli index 6ace647e813..d8e8b9819c9 100644 --- a/src/plugins/e-acsl/quantif.mli +++ b/src/plugins/e-acsl/quantif.mli @@ -32,12 +32,9 @@ val quantif_to_exp: (** {2 Forward references} *) (* ***********************************************************************) -val predicate_to_exp_ref: +val predicate_to_exp_ref: (kernel_function -> Env.t -> predicate -> exp * Env.t) ref -val term_to_exp_ref: - (kernel_function -> Env.t -> term -> exp * Env.t) ref - (* Local Variables: compile-command: "make" diff --git a/src/plugins/e-acsl/tests/gmp/at_on-purely-logic-variables.c b/src/plugins/e-acsl/tests/gmp/at_on-purely-logic-variables.c index bd8d99e51fc..ef6ee47e377 100644 --- a/src/plugins/e-acsl/tests/gmp/at_on-purely-logic-variables.c +++ b/src/plugins/e-acsl/tests/gmp/at_on-purely-logic-variables.c @@ -49,6 +49,15 @@ int main(void) { f(t); g(); + // Name capturing + /*@ assert + \exists integer u; 10 <= u < 20 + && \exists integer v; -10 < v <= -5 + (\let u = -2; u) // another u + && \exists integer w; 100 < w <= 200 + && \at(n - u + + (\let u = 42; u) // yet another u + + v + w > 0, K); */ ; + // Not yet: /*@ assert \exists integer j; 2 <= j < 10000000000000000 // too big => not_yet diff --git a/src/plugins/e-acsl/tests/gmp/oracle/at_on-purely-logic-variables.0.res.oracle b/src/plugins/e-acsl/tests/gmp/oracle/at_on-purely-logic-variables.0.res.oracle index f84b17a3b0c..c0ae2df3d3e 100644 --- a/src/plugins/e-acsl/tests/gmp/oracle/at_on-purely-logic-variables.0.res.oracle +++ b/src/plugins/e-acsl/tests/gmp/oracle/at_on-purely-logic-variables.0.res.oracle @@ -1,10 +1,10 @@ [e-acsl] beginning translation. -[e-acsl] tests/gmp/at_on-purely-logic-variables.c:55: Warning: +[e-acsl] tests/gmp/at_on-purely-logic-variables.c:64: Warning: E-ACSL construct `\at on purely logic variables that needs to allocate too much memory (bigger than int_max bytes)' is not yet supported. Ignoring annotation. -[e-acsl] tests/gmp/at_on-purely-logic-variables.c:56: Warning: +[e-acsl] tests/gmp/at_on-purely-logic-variables.c:65: Warning: E-ACSL construct `\at with logic variable linked to C variable' is not yet supported. Ignoring annotation. @@ -19,6 +19,8 @@ __e_acsl_math_HUGE_VALF ∈ [-3.40282346639e+38 .. 3.40282346639e+38] __e_acsl_math_INFINITY ∈ [-1.79769313486e+308 .. 1.79769313486e+308] [eva] using specification for function __e_acsl_memory_init +[eva] tests/gmp/at_on-purely-logic-variables.c:57: + allocating variable __malloc_main_l57 [eva] tests/gmp/at_on-purely-logic-variables.c:45: allocating variable __malloc_main_l45 [eva] tests/gmp/at_on-purely-logic-variables.c:41: @@ -42,27 +44,29 @@ starting to merge loop iterations [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:28: Warning: out of bounds write. assert \valid(__gen_e_acsl_at + 0); +[eva:alarm] tests/gmp/at_on-purely-logic-variables.c:57: Warning: + out of bounds write. + assert + \valid(__gen_e_acsl_at_7 + + (int)((int)((int)(__gen_e_acsl_u_6 - 10) * 300) + + (int)((int)((int)((int)(__gen_e_acsl_v_6 - -10) - 1) * 100) + + (int)((int)(__gen_e_acsl_w_2 - 100) - 1)))); +[eva] tests/gmp/at_on-purely-logic-variables.c:57: + starting to merge loop iterations [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:45: Warning: out of bounds write. assert \valid(__gen_e_acsl_at_6 + (int)((int)((int)(__gen_e_acsl_u_4 - 9) * 32) + - (int)(__gen_e_acsl_v_4 - -4))); + (int)((int)(__gen_e_acsl_v_4 - -5) - 1))); [eva] tests/gmp/at_on-purely-logic-variables.c:45: starting to merge loop iterations -[eva:alarm] tests/gmp/at_on-purely-logic-variables.c:45: Warning: - signed overflow. assert __gen_e_acsl_v_4 - -4 ≤ 2147483647; -[eva:alarm] tests/gmp/at_on-purely-logic-variables.c:45: Warning: - signed overflow. - assert - (int)((int)(__gen_e_acsl_u_4 - 9) * 32) + (int)(__gen_e_acsl_v_4 - -4) ≤ - 2147483647; [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:34: Warning: out of bounds write. assert \valid(__gen_e_acsl_at_3 + (int)((int)((int)(__gen_e_acsl_u_2 - 9) * 11) + - (int)(__gen_e_acsl_v_2 - -4))); + (int)((int)(__gen_e_acsl_v_2 - -5) - 1))); [eva] tests/gmp/at_on-purely-logic-variables.c:34: starting to merge loop iterations [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:28: Warning: @@ -91,20 +95,20 @@ accessing uninitialized left-value. assert \initialized(__gen_e_acsl_at_3 + - ((__gen_e_acsl_u - 9) * 11 + (__gen_e_acsl_v - -4))); + ((__gen_e_acsl_u - 9) * 11 + ((__gen_e_acsl_v - -5) - 1))); [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:33: Warning: out of bounds read. assert \valid_read(__gen_e_acsl_at_3 + (int)((int)((int)(__gen_e_acsl_u - 9) * 11) + - (int)(__gen_e_acsl_v - -4))); + (int)((int)(__gen_e_acsl_v - -5) - 1))); [eva] tests/gmp/at_on-purely-logic-variables.c:33: starting to merge loop iterations [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:37: Warning: assertion got status unknown. [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:41: Warning: out of bounds write. - assert \valid(__gen_e_acsl_at_5 + (int)(__gen_e_acsl_k_4 - -8)); + assert \valid(__gen_e_acsl_at_5 + (int)((int)(__gen_e_acsl_k_4 - -9) - 1)); [eva] tests/gmp/at_on-purely-logic-variables.c:41: starting to merge loop iterations [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:41: Warning: @@ -113,10 +117,11 @@ function __e_acsl_assert: precondition got status unknown. [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:41: Warning: accessing uninitialized left-value. - assert \initialized(__gen_e_acsl_at_5 + (__gen_e_acsl_k_3 - -8)); + assert \initialized(__gen_e_acsl_at_5 + ((__gen_e_acsl_k_3 - -9) - 1)); [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:41: Warning: out of bounds read. - assert \valid_read(__gen_e_acsl_at_5 + (int)(__gen_e_acsl_k_3 - -8)); + assert + \valid_read(__gen_e_acsl_at_5 + (int)((int)(__gen_e_acsl_k_3 - -9) - 1)); [eva] tests/gmp/at_on-purely-logic-variables.c:41: starting to merge loop iterations [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:41: Warning: @@ -129,13 +134,13 @@ accessing uninitialized left-value. assert \initialized(__gen_e_acsl_at_6 + - ((__gen_e_acsl_u_3 - 9) * 32 + (__gen_e_acsl_v_3 - -4))); + ((__gen_e_acsl_u_3 - 9) * 32 + ((__gen_e_acsl_v_3 - -5) - 1))); [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:44: Warning: out of bounds read. assert \valid_read(__gen_e_acsl_at_6 + (int)((int)((int)(__gen_e_acsl_u_3 - 9) * 32) + - (int)(__gen_e_acsl_v_3 - -4))); + (int)((int)(__gen_e_acsl_v_3 - -5) - 1))); [eva] tests/gmp/at_on-purely-logic-variables.c:44: starting to merge loop iterations [eva] tests/gmp/at_on-purely-logic-variables.c:8: @@ -152,12 +157,12 @@ out of bounds write. assert \valid(__gen_e_acsl_at_3 + 0); [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:7: Warning: out of bounds write. - assert \valid(__gen_e_acsl_at_2 + (int)(__gen_e_acsl_n_3 - 2)); + assert \valid(__gen_e_acsl_at_2 + (int)((int)(__gen_e_acsl_n_3 - 1) - 1)); [eva] tests/gmp/at_on-purely-logic-variables.c:7: starting to merge loop iterations [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:7: Warning: out of bounds write. - assert \valid(__gen_e_acsl_at + (int)(__gen_e_acsl_n_2 - 2)); + assert \valid(__gen_e_acsl_at + (int)((int)(__gen_e_acsl_n_2 - 1) - 1)); [eva] tests/gmp/at_on-purely-logic-variables.c:7: starting to merge loop iterations [eva] using specification for function __e_acsl_delete_block @@ -165,18 +170,18 @@ function __e_acsl_assert: precondition got status unknown. [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:7: Warning: accessing uninitialized left-value. - assert \initialized(__gen_e_acsl_at + (__gen_e_acsl_n - 2)); + assert \initialized(__gen_e_acsl_at + ((__gen_e_acsl_n - 1) - 1)); [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:7: Warning: out of bounds read. - assert \valid_read(__gen_e_acsl_at + (int)(__gen_e_acsl_n - 2)); + assert \valid_read(__gen_e_acsl_at + (int)((int)(__gen_e_acsl_n - 1) - 1)); [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:7: Warning: function __e_acsl_assert: precondition got status unknown. [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:7: Warning: accessing uninitialized left-value. - assert \initialized(__gen_e_acsl_at_2 + (__gen_e_acsl_n - 2)); + assert \initialized(__gen_e_acsl_at_2 + ((__gen_e_acsl_n - 1) - 1)); [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:7: Warning: out of bounds read. - assert \valid_read(__gen_e_acsl_at_2 + (int)(__gen_e_acsl_n - 2)); + assert \valid_read(__gen_e_acsl_at_2 + (int)((int)(__gen_e_acsl_n - 1) - 1)); [eva] tests/gmp/at_on-purely-logic-variables.c:6: starting to merge loop iterations [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:6: Warning: @@ -206,7 +211,25 @@ function __e_acsl_assert: precondition got status unknown. [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:54: Warning: assertion got status unknown. +[eva:alarm] tests/gmp/at_on-purely-logic-variables.c:57: Warning: + function __e_acsl_assert: precondition got status unknown. +[eva:alarm] tests/gmp/at_on-purely-logic-variables.c:56: Warning: + accessing uninitialized left-value. + assert + \initialized(__gen_e_acsl_at_7 + + ((__gen_e_acsl_u_5 - 10) * 300 + + (((__gen_e_acsl_v_5 - -10) - 1) * 100 + + ((__gen_e_acsl_w - 100) - 1)))); [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:56: Warning: + out of bounds read. + assert + \valid_read(__gen_e_acsl_at_7 + + (int)((int)((int)(__gen_e_acsl_u_5 - 10) * 300) + + (int)((int)((int)((int)(__gen_e_acsl_v_5 - -10) - 1) * 100) + + (int)((int)(__gen_e_acsl_w - 100) - 1)))); +[eva:alarm] tests/gmp/at_on-purely-logic-variables.c:63: Warning: + assertion got status unknown. +[eva:alarm] tests/gmp/at_on-purely-logic-variables.c:65: Warning: assertion got status unknown. [eva] using specification for function __e_acsl_memory_clean [eva] done for function main diff --git a/src/plugins/e-acsl/tests/gmp/oracle/at_on-purely-logic-variables.1.res.oracle b/src/plugins/e-acsl/tests/gmp/oracle/at_on-purely-logic-variables.1.res.oracle index 6cd8b6b75df..1e6a8533f45 100644 --- a/src/plugins/e-acsl/tests/gmp/oracle/at_on-purely-logic-variables.1.res.oracle +++ b/src/plugins/e-acsl/tests/gmp/oracle/at_on-purely-logic-variables.1.res.oracle @@ -32,12 +32,17 @@ `\at on purely logic variables and with quantifier that uses too complex bound (E-ACSL cannot infer a finite upper bound to it)' is not yet supported. Ignoring annotation. -[e-acsl] tests/gmp/at_on-purely-logic-variables.c:55: Warning: +[e-acsl] tests/gmp/at_on-purely-logic-variables.c:57: Warning: E-ACSL construct `\at on purely logic variables that needs to allocate too much memory (bigger than int_max bytes)' is not yet supported. Ignoring annotation. -[e-acsl] tests/gmp/at_on-purely-logic-variables.c:56: Warning: +[e-acsl] tests/gmp/at_on-purely-logic-variables.c:64: Warning: + E-ACSL construct + `\at on purely logic variables that needs to allocate too much memory (bigger than int_max bytes)' + is not yet supported. + Ignoring annotation. +[e-acsl] tests/gmp/at_on-purely-logic-variables.c:65: Warning: E-ACSL construct `\at with logic variable linked to C variable' is not yet supported. Ignoring annotation. @@ -85,7 +90,9 @@ assertion got status unknown. [eva:alarm] tests/gmp/at_on-purely-logic-variables.c:54: Warning: assertion got status unknown. -[eva:alarm] tests/gmp/at_on-purely-logic-variables.c:56: Warning: +[eva:alarm] tests/gmp/at_on-purely-logic-variables.c:63: Warning: + assertion got status unknown. +[eva:alarm] tests/gmp/at_on-purely-logic-variables.c:65: Warning: assertion got status unknown. [eva] using specification for function __e_acsl_memory_clean [eva] done for function main diff --git a/src/plugins/e-acsl/tests/gmp/oracle/gen_at_on-purely-logic-variables.c b/src/plugins/e-acsl/tests/gmp/oracle/gen_at_on-purely-logic-variables.c index 8fdcd544b06..fa086a5115b 100644 --- a/src/plugins/e-acsl/tests/gmp/oracle/gen_at_on-purely-logic-variables.c +++ b/src/plugins/e-acsl/tests/gmp/oracle/gen_at_on-purely-logic-variables.c @@ -26,16 +26,15 @@ void g(void) { int __gen_e_acsl_w_2; __gen_e_acsl_w_2 = 3; - while (1) - if (__gen_e_acsl_w_2 <= 5) { - /*@ assert - Value: mem_access: - \valid(__gen_e_acsl_at + (int)(__gen_e_acsl_w_2 - 3)); - */ - *(__gen_e_acsl_at + (__gen_e_acsl_w_2 - 3)) = m + (long)__gen_e_acsl_w_2 == 12L; - __gen_e_acsl_w_2 ++; - } - else break; + while (1) { + if (__gen_e_acsl_w_2 < 6) ; else break; + /*@ assert + Value: mem_access: + \valid(__gen_e_acsl_at + (int)(__gen_e_acsl_w_2 - 3)); + */ + *(__gen_e_acsl_at + (__gen_e_acsl_w_2 - 3)) = m + (long)__gen_e_acsl_w_2 == 12L; + __gen_e_acsl_w_2 ++; + } } ; } @@ -85,6 +84,7 @@ void g(void) int main(void) { + int *__gen_e_acsl_at_7; int *__gen_e_acsl_at_6; long *__gen_e_acsl_at_5; long *__gen_e_acsl_at_4; @@ -94,6 +94,7 @@ int main(void) int __retres; int n; __e_acsl_memory_init((int *)0,(char ***)0,(size_t)8); + __gen_e_acsl_at_7 = (int *)malloc((size_t)12000); __gen_e_acsl_at_6 = (int *)malloc((size_t)1536); __gen_e_acsl_at_5 = (long *)malloc((size_t)64); __gen_e_acsl_at_4 = (long *)malloc((size_t)8); @@ -114,16 +115,15 @@ int main(void) { int __gen_e_acsl_j_2; __gen_e_acsl_j_2 = 2; - while (1) - if (__gen_e_acsl_j_2 <= 4) { - /*@ assert - Value: mem_access: - \valid(__gen_e_acsl_at_2 + (int)(__gen_e_acsl_j_2 - 2)); - */ - *(__gen_e_acsl_at_2 + (__gen_e_acsl_j_2 - 2)) = n + (long)__gen_e_acsl_j_2 == 11L; - __gen_e_acsl_j_2 ++; - } - else break; + while (1) { + if (__gen_e_acsl_j_2 < 5) ; else break; + /*@ assert + Value: mem_access: + \valid(__gen_e_acsl_at_2 + (int)(__gen_e_acsl_j_2 - 2)); + */ + *(__gen_e_acsl_at_2 + (__gen_e_acsl_j_2 - 2)) = n + (long)__gen_e_acsl_j_2 == 11L; + __gen_e_acsl_j_2 ++; + } } { int __gen_e_acsl_i_2; @@ -137,78 +137,104 @@ int main(void) n = 9; K: { + { + int __gen_e_acsl_u_6; + int __gen_e_acsl_v_6; + int __gen_e_acsl_w_2; + __gen_e_acsl_u_6 = 10; + while (1) { + if (__gen_e_acsl_u_6 < 20) ; else break; + __gen_e_acsl_v_6 = -10 + 1; + while (1) { + { + int __gen_e_acsl_u_8; + __gen_e_acsl_u_8 = -2; + if (__gen_e_acsl_v_6 <= -5 + __gen_e_acsl_u_8) ; else break; + } + __gen_e_acsl_w_2 = 100 + 1; + while (1) { + if (__gen_e_acsl_w_2 <= 200) ; else break; + { + int __gen_e_acsl_u_7; + __gen_e_acsl_u_7 = 42; + /*@ assert + Value: mem_access: + \valid(__gen_e_acsl_at_7 + + (int)((int)((int)(__gen_e_acsl_u_6 - 10) * 300) + + (int)((int)((int)((int)(__gen_e_acsl_v_6 - + -10) + - 1) + * 100) + + + (int)((int)(__gen_e_acsl_w_2 - 100) - + 1)))); + */ + *(__gen_e_acsl_at_7 + ((__gen_e_acsl_u_6 - 10) * 300 + ( + ((__gen_e_acsl_v_6 - -10) - 1) * 100 + ( + (__gen_e_acsl_w_2 - 100) - 1)))) = + (((n - (long)__gen_e_acsl_u_6) + __gen_e_acsl_u_7) + __gen_e_acsl_v_6) + __gen_e_acsl_w_2 > 0L; + } + __gen_e_acsl_w_2 ++; + } + __gen_e_acsl_v_6 ++; + } + __gen_e_acsl_u_6 ++; + } + } { int __gen_e_acsl_u_4; + int __gen_e_acsl_v_4; __gen_e_acsl_u_4 = 9; - while (1) - if (__gen_e_acsl_u_4 <= 20) { + while (1) { + if (__gen_e_acsl_u_4 < 21) ; else break; + __gen_e_acsl_v_4 = -5 + 1; + while (1) { { - int __gen_e_acsl_v_4; int __gen_e_acsl_if_2; if (__gen_e_acsl_u_4 < 15) __gen_e_acsl_if_2 = __gen_e_acsl_u_4 + 6; else __gen_e_acsl_if_2 = 3; - __gen_e_acsl_v_4 = -5 + 1; - while (1) - if (__gen_e_acsl_v_4 <= __gen_e_acsl_if_2) { - /*@ assert - Value: mem_access: - \valid(__gen_e_acsl_at_6 + - (int)((int)((int)(__gen_e_acsl_u_4 - 9) * 32) + - (int)(__gen_e_acsl_v_4 - -4))); - */ - /*@ assert - Value: signed_overflow: - __gen_e_acsl_v_4 - -4 ≤ 2147483647; - */ - /*@ assert - Value: signed_overflow: - (int)((int)(__gen_e_acsl_u_4 - 9) * 32) + - (int)(__gen_e_acsl_v_4 - -4) ≤ 2147483647; - */ - *(__gen_e_acsl_at_6 + ((__gen_e_acsl_u_4 - 9) * 32 + ( - __gen_e_acsl_v_4 - -4))) = (n + (long)__gen_e_acsl_u_4) + n > 0L; - __gen_e_acsl_v_4 ++; - } - else break; + if (__gen_e_acsl_v_4 <= __gen_e_acsl_if_2) ; else break; } - __gen_e_acsl_u_4 ++; + /*@ assert + Value: mem_access: + \valid(__gen_e_acsl_at_6 + + (int)((int)((int)(__gen_e_acsl_u_4 - 9) * 32) + + (int)((int)(__gen_e_acsl_v_4 - -5) - 1))); + */ + *(__gen_e_acsl_at_6 + ((__gen_e_acsl_u_4 - 9) * 32 + ((__gen_e_acsl_v_4 - -5) - 1))) = + (n + (long)__gen_e_acsl_u_4) + n > 0L; + __gen_e_acsl_v_4 ++; } - else break; + __gen_e_acsl_u_4 ++; + } } { int __gen_e_acsl_k_2; - { - int __gen_e_acsl_u_2; - __gen_e_acsl_k_2 = -7; - __gen_e_acsl_u_2 = 9; - while (1) - if (__gen_e_acsl_u_2 <= 20) { - { - int __gen_e_acsl_v_2; - __gen_e_acsl_v_2 = -5 + 1; - while (1) - if (__gen_e_acsl_v_2 <= 6) { - { - long __gen_e_acsl_if; - if (__gen_e_acsl_u_2 > 0) __gen_e_acsl_if = n + (long)__gen_e_acsl_k_2; - else __gen_e_acsl_if = __gen_e_acsl_u_2 + __gen_e_acsl_v_2; - /*@ assert - Value: mem_access: - \valid(__gen_e_acsl_at_3 + - (int)((int)((int)(__gen_e_acsl_u_2 - 9) * 11) - + (int)(__gen_e_acsl_v_2 - -4))); - */ - *(__gen_e_acsl_at_3 + ((__gen_e_acsl_u_2 - 9) * 11 + ( - __gen_e_acsl_v_2 - -4))) = - __gen_e_acsl_if > 0L; - } - __gen_e_acsl_v_2 ++; - } - else break; - } - __gen_e_acsl_u_2 ++; + int __gen_e_acsl_u_2; + int __gen_e_acsl_v_2; + __gen_e_acsl_k_2 = -7; + __gen_e_acsl_u_2 = 9; + while (1) { + if (__gen_e_acsl_u_2 < 21) ; else break; + __gen_e_acsl_v_2 = -5 + 1; + while (1) { + if (__gen_e_acsl_v_2 <= 6) ; else break; + { + long __gen_e_acsl_if; + if (__gen_e_acsl_u_2 > 0) __gen_e_acsl_if = n + (long)__gen_e_acsl_k_2; + else __gen_e_acsl_if = __gen_e_acsl_u_2 + __gen_e_acsl_v_2; + /*@ assert + Value: mem_access: + \valid(__gen_e_acsl_at_3 + + (int)((int)((int)(__gen_e_acsl_u_2 - 9) * 11) + + (int)((int)(__gen_e_acsl_v_2 - -5) - 1))); + */ + *(__gen_e_acsl_at_3 + ((__gen_e_acsl_u_2 - 9) * 11 + ((__gen_e_acsl_v_2 - -5) - 1))) = + __gen_e_acsl_if > 0L; } - else break; + __gen_e_acsl_v_2 ++; + } + __gen_e_acsl_u_2 ++; } } ; @@ -299,27 +325,28 @@ int main(void) (long)((int)( (long)((int)( __gen_e_acsl_u - 9L)) * 11L)) + (int)( - __gen_e_acsl_v - -4L))), + (int)(__gen_e_acsl_v - -5L) - 1))), sizeof(int), (void *)__gen_e_acsl_at_3, (void *)(& __gen_e_acsl_at_3)); __e_acsl_assert(__gen_e_acsl_valid_read_3,(char *)"RTE", (char *)"main", - (char *)"mem_access:\n \\valid_read(__gen_e_acsl_at_3 +\n (int)((int)((int)(__gen_e_acsl_u - 9) * 11) +\n (int)(__gen_e_acsl_v - -4)))", + (char *)"mem_access:\n \\valid_read(__gen_e_acsl_at_3 +\n (int)((int)((int)(__gen_e_acsl_u - 9) * 11) +\n (int)((int)(__gen_e_acsl_v - -5) - 1)))", 34); /*@ assert Value: initialization: \initialized(__gen_e_acsl_at_3 + ((__gen_e_acsl_u - 9) * 11 + - (__gen_e_acsl_v - -4))); + ((__gen_e_acsl_v - -5) - 1))); */ /*@ assert Value: mem_access: \valid_read(__gen_e_acsl_at_3 + (int)((int)((int)(__gen_e_acsl_u - 9) * 11) + - (int)(__gen_e_acsl_v - -4))); + (int)((int)(__gen_e_acsl_v - -5) - 1))); */ - if (*(__gen_e_acsl_at_3 + ((__gen_e_acsl_u - 9) * 11 + (__gen_e_acsl_v - -4)))) + if (*(__gen_e_acsl_at_3 + ((__gen_e_acsl_u - 9) * 11 + (( + __gen_e_acsl_v - -5) - 1)))) ; else { __gen_e_acsl_forall = 0; @@ -364,16 +391,16 @@ int main(void) { int __gen_e_acsl_k_4; __gen_e_acsl_k_4 = -9 + 1; - while (1) - if (__gen_e_acsl_k_4 <= -1) { - /*@ assert - Value: mem_access: - \valid(__gen_e_acsl_at_5 + (int)(__gen_e_acsl_k_4 - -8)); - */ - *(__gen_e_acsl_at_5 + (__gen_e_acsl_k_4 - -8)) = m + (long)__gen_e_acsl_k_4; - __gen_e_acsl_k_4 ++; - } - else break; + while (1) { + if (__gen_e_acsl_k_4 < 0) ; else break; + /*@ assert + Value: mem_access: + \valid(__gen_e_acsl_at_5 + + (int)((int)(__gen_e_acsl_k_4 - -9) - 1)); + */ + *(__gen_e_acsl_at_5 + ((__gen_e_acsl_k_4 - -9) - 1)) = m + (long)__gen_e_acsl_k_4; + __gen_e_acsl_k_4 ++; + } } ; } @@ -388,24 +415,26 @@ int main(void) if (__gen_e_acsl_k_3 < 0) ; else break; { int __gen_e_acsl_valid_read_5; - __gen_e_acsl_valid_read_5 = __e_acsl_valid_read((void *)(__gen_e_acsl_at_5 + (int)( - __gen_e_acsl_k_3 - -8L)), + __gen_e_acsl_valid_read_5 = __e_acsl_valid_read((void *)(__gen_e_acsl_at_5 + ( + (int)( + __gen_e_acsl_k_3 - -9L) - 1)), sizeof(long), (void *)__gen_e_acsl_at_5, (void *)(& __gen_e_acsl_at_5)); __e_acsl_assert(__gen_e_acsl_valid_read_5,(char *)"RTE", (char *)"main", - (char *)"mem_access: \\valid_read(__gen_e_acsl_at_5 + (int)(__gen_e_acsl_k_3 - -8))", + (char *)"mem_access:\n \\valid_read(__gen_e_acsl_at_5 + (int)((int)(__gen_e_acsl_k_3 - -9) - 1))", 41); /*@ assert Value: initialization: - \initialized(__gen_e_acsl_at_5 + (__gen_e_acsl_k_3 - -8)); + \initialized(__gen_e_acsl_at_5 + ((__gen_e_acsl_k_3 - -9) - 1)); */ /*@ assert Value: mem_access: - \valid_read(__gen_e_acsl_at_5 + (int)(__gen_e_acsl_k_3 - -8)); + \valid_read(__gen_e_acsl_at_5 + + (int)((int)(__gen_e_acsl_k_3 - -9) - 1)); */ - if (! (*(__gen_e_acsl_at_5 + (__gen_e_acsl_k_3 - -8)) == 0L)) + if (! (*(__gen_e_acsl_at_5 + ((__gen_e_acsl_k_3 - -9) - 1)) == 0L)) ; else { __gen_e_acsl_exists_3 = 1; @@ -450,28 +479,29 @@ int main(void) (long)((int)( (long)((int)( __gen_e_acsl_u_3 - 9L)) * 32L)) + (int)( - __gen_e_acsl_v_3 - -4L))), + (int)(__gen_e_acsl_v_3 - -5L) - 1))), sizeof(int), (void *)__gen_e_acsl_at_6, (void *)(& __gen_e_acsl_at_6)); __e_acsl_assert(__gen_e_acsl_valid_read_6,(char *)"RTE", (char *)"main", - (char *)"mem_access:\n \\valid_read(__gen_e_acsl_at_6 +\n (int)((int)((int)(__gen_e_acsl_u_3 - 9) * 32) +\n (int)(__gen_e_acsl_v_3 - -4)))", + (char *)"mem_access:\n \\valid_read(__gen_e_acsl_at_6 +\n (int)((int)((int)(__gen_e_acsl_u_3 - 9) * 32) +\n (int)((int)(__gen_e_acsl_v_3 - -5) - 1)))", 45); /*@ assert Value: initialization: \initialized(__gen_e_acsl_at_6 + ((__gen_e_acsl_u_3 - 9) * 32 + - (__gen_e_acsl_v_3 - -4))); + ((__gen_e_acsl_v_3 - -5) - 1))); */ /*@ assert Value: mem_access: \valid_read(__gen_e_acsl_at_6 + (int)((int)((int)(__gen_e_acsl_u_3 - 9) * 32) + - (int)(__gen_e_acsl_v_3 - -4))); + (int)((int)(__gen_e_acsl_v_3 - -5) - 1))); */ if (*(__gen_e_acsl_at_6 + ((__gen_e_acsl_u_3 - 9) * 32 + ( - __gen_e_acsl_v_3 - -4)))) ; + (__gen_e_acsl_v_3 - -5) - 1)))) + ; else { __gen_e_acsl_forall_2 = 0; goto e_acsl_end_loop6; @@ -498,6 +528,116 @@ int main(void) __e_acsl_full_init((void *)(& t)); __gen_e_acsl_f(t); g(); + /*@ assert + ∃ ℤ u; + 10 ≤ u < 20 ∧ + (∃ ℤ v; + -10 < v ≤ -5 + (\let u = -2; u) ∧ + (∃ ℤ w; + 100 < w ≤ 200 ∧ + \at((((n - u) + (\let u = 42; u)) + v) + w > 0,K))); + */ + { + int __gen_e_acsl_exists_5; + int __gen_e_acsl_u_5; + __gen_e_acsl_exists_5 = 0; + __gen_e_acsl_u_5 = 10; + while (1) { + if (__gen_e_acsl_u_5 < 20) ; else break; + { + int __gen_e_acsl_exists_6; + int __gen_e_acsl_v_5; + __gen_e_acsl_exists_6 = 0; + __gen_e_acsl_v_5 = -10 + 1; + while (1) { + { + int __gen_e_acsl_u_9; + __gen_e_acsl_u_9 = -2; + if (__gen_e_acsl_v_5 <= -5 + __gen_e_acsl_u_9) ; else break; + } + { + int __gen_e_acsl_exists_7; + int __gen_e_acsl_w; + __gen_e_acsl_exists_7 = 0; + __gen_e_acsl_w = 100 + 1; + while (1) { + if (__gen_e_acsl_w <= 200) ; else break; + { + int __gen_e_acsl_valid_read_7; + __gen_e_acsl_valid_read_7 = __e_acsl_valid_read((void *)( + __gen_e_acsl_at_7 + (int)( + (long)((int)( + (long)((int)( + __gen_e_acsl_u_5 - 10L)) * 300L)) + (int)( + (long)((int)( + (long)((int)( + (int)( + __gen_e_acsl_v_5 - -10L) - 1)) * 100L)) + (int)( + (long)((int)( + __gen_e_acsl_w - 100L)) - 1L)))), + sizeof(int), + (void *)__gen_e_acsl_at_7, + (void *)(& __gen_e_acsl_at_7)); + __e_acsl_assert(__gen_e_acsl_valid_read_7,(char *)"RTE", + (char *)"main", + (char *)"mem_access:\n \\valid_read(__gen_e_acsl_at_7 +\n (int)((int)((int)(__gen_e_acsl_u_5 - 10) * 300) +\n (int)((int)((int)((int)(__gen_e_acsl_v_5 - -10) - 1) *\n 100)\n + (int)((int)(__gen_e_acsl_w - 100) - 1))))", + 57); + /*@ assert + Value: initialization: + \initialized(__gen_e_acsl_at_7 + + ((__gen_e_acsl_u_5 - 10) * 300 + + (((__gen_e_acsl_v_5 - -10) - 1) * 100 + + ((__gen_e_acsl_w - 100) - 1)))); + */ + /*@ assert + Value: mem_access: + \valid_read(__gen_e_acsl_at_7 + + (int)((int)((int)(__gen_e_acsl_u_5 - 10) * + 300) + + + (int)((int)((int)((int)(__gen_e_acsl_v_5 + - -10) + - 1) + * 100) + + + (int)((int)(__gen_e_acsl_w - + 100) + - 1)))); + */ + if (! *(__gen_e_acsl_at_7 + ((__gen_e_acsl_u_5 - 10) * 300 + ( + ((__gen_e_acsl_v_5 - -10) - 1) * 100 + ( + (__gen_e_acsl_w - 100) - 1))))) + ; + else { + __gen_e_acsl_exists_7 = 1; + goto e_acsl_end_loop8; + } + } + __gen_e_acsl_w ++; + } + e_acsl_end_loop8: ; + if (! __gen_e_acsl_exists_7) ; + else { + __gen_e_acsl_exists_6 = 1; + goto e_acsl_end_loop9; + } + } + __gen_e_acsl_v_5 ++; + } + e_acsl_end_loop9: ; + if (! __gen_e_acsl_exists_6) ; + else { + __gen_e_acsl_exists_5 = 1; + goto e_acsl_end_loop10; + } + } + __gen_e_acsl_u_5 ++; + } + e_acsl_end_loop10: ; + __e_acsl_assert(__gen_e_acsl_exists_5,(char *)"Assertion",(char *)"main", + (char *)"\\exists integer u;\n 10 <= u < 20 &&\n (\\exists integer v;\n -10 < v <= -5 + (\\let u = -2; u) &&\n (\\exists integer w;\n 100 < w <= 200 && \\at((((n - u) + (\\let u = 42; u)) + v) + w > 0,K)))", + 54); + } /*@ assert ∃ ℤ j; 2 ≤ j < 10000000000000000 ∧ \at(n + j ≡ 11,L); */ ; @@ -505,6 +645,7 @@ int main(void) __retres = 0; __e_acsl_delete_block((void *)(t)); __e_acsl_delete_block((void *)(& n)); + free((void *)__gen_e_acsl_at_7); free((void *)__gen_e_acsl_at_6); free((void *)__gen_e_acsl_at_5); free((void *)__gen_e_acsl_at_4); @@ -545,30 +686,28 @@ void __gen_e_acsl_f(int *t) { int __gen_e_acsl_n_3; __gen_e_acsl_n_3 = 1 + 1; - while (1) - if (__gen_e_acsl_n_3 <= 3) { - /*@ assert - Value: mem_access: - \valid(__gen_e_acsl_at_2 + (int)(__gen_e_acsl_n_3 - 2)); - */ - *(__gen_e_acsl_at_2 + (__gen_e_acsl_n_3 - 2)) = *(t + (__gen_e_acsl_n_3 - 1)) > 5; - __gen_e_acsl_n_3 ++; - } - else break; + while (1) { + if (__gen_e_acsl_n_3 <= 3) ; else break; + /*@ assert + Value: mem_access: + \valid(__gen_e_acsl_at_2 + (int)((int)(__gen_e_acsl_n_3 - 1) - 1)); + */ + *(__gen_e_acsl_at_2 + ((__gen_e_acsl_n_3 - 1) - 1)) = *(t + (__gen_e_acsl_n_3 - 1)) > 5; + __gen_e_acsl_n_3 ++; + } } { int __gen_e_acsl_n_2; __gen_e_acsl_n_2 = 1 + 1; - while (1) - if (__gen_e_acsl_n_2 <= 3) { - /*@ assert - Value: mem_access: - \valid(__gen_e_acsl_at + (int)(__gen_e_acsl_n_2 - 2)); - */ - *(__gen_e_acsl_at + (__gen_e_acsl_n_2 - 2)) = *(t + __gen_e_acsl_n_2) == 12; - __gen_e_acsl_n_2 ++; - } - else break; + while (1) { + if (__gen_e_acsl_n_2 <= 3) ; else break; + /*@ assert + Value: mem_access: + \valid(__gen_e_acsl_at + (int)((int)(__gen_e_acsl_n_2 - 1) - 1)); + */ + *(__gen_e_acsl_at + ((__gen_e_acsl_n_2 - 1) - 1)) = *(t + __gen_e_acsl_n_2) == 12; + __gen_e_acsl_n_2 ++; + } } __e_acsl_store_block((void *)(& t),(size_t)8); f(t); @@ -586,52 +725,56 @@ void __gen_e_acsl_f(int *t) int __gen_e_acsl_valid_read; int __gen_e_acsl_and; __gen_e_acsl_valid_read = __e_acsl_valid_read((void *)(__gen_e_acsl_at + (int)( - __gen_e_acsl_n - 2L)), + (long)((int)( + __gen_e_acsl_n - 1L)) - 1L)), sizeof(int), (void *)__gen_e_acsl_at, (void *)(& __gen_e_acsl_at)); __e_acsl_assert(__gen_e_acsl_valid_read,(char *)"RTE",(char *)"f", - (char *)"mem_access: \\valid_read(__gen_e_acsl_at + (int)(__gen_e_acsl_n - 2))", + (char *)"mem_access:\n \\valid_read(__gen_e_acsl_at + (int)((int)(__gen_e_acsl_n - 1) - 1))", 7); /*@ assert Value: initialization: - \initialized(__gen_e_acsl_at + (__gen_e_acsl_n - 2)); + \initialized(__gen_e_acsl_at + ((__gen_e_acsl_n - 1) - 1)); */ /*@ assert Value: mem_access: - \valid_read(__gen_e_acsl_at + (int)(__gen_e_acsl_n - 2)); + \valid_read(__gen_e_acsl_at + + (int)((int)(__gen_e_acsl_n - 1) - 1)); */ - if (*(__gen_e_acsl_at + (__gen_e_acsl_n - 2))) { + if (*(__gen_e_acsl_at + ((__gen_e_acsl_n - 1) - 1))) { int __gen_e_acsl_valid_read_2; __gen_e_acsl_valid_read_2 = __e_acsl_valid_read((void *)(__gen_e_acsl_at_2 + (int)( - __gen_e_acsl_n - 2L)), + (long)((int)( + __gen_e_acsl_n - 1L)) - 1L)), 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 + (int)(__gen_e_acsl_n - 2))", + (char *)"mem_access:\n \\valid_read(__gen_e_acsl_at_2 + (int)((int)(__gen_e_acsl_n - 1) - 1))", 7); /*@ assert Value: initialization: - \initialized(__gen_e_acsl_at_2 + (__gen_e_acsl_n - 2)); + \initialized(__gen_e_acsl_at_2 + ((__gen_e_acsl_n - 1) - 1)); */ /*@ assert Value: mem_access: - \valid_read(__gen_e_acsl_at_2 + (int)(__gen_e_acsl_n - 2)); + \valid_read(__gen_e_acsl_at_2 + + (int)((int)(__gen_e_acsl_n - 1) - 1)); */ - __gen_e_acsl_and = *(__gen_e_acsl_at_2 + (__gen_e_acsl_n - 2)); + __gen_e_acsl_and = *(__gen_e_acsl_at_2 + ((__gen_e_acsl_n - 1) - 1)); } else __gen_e_acsl_and = 0; if (__gen_e_acsl_and) ; else { __gen_e_acsl_forall = 0; - goto e_acsl_end_loop8; + goto e_acsl_end_loop11; } } __gen_e_acsl_n ++; } - e_acsl_end_loop8: ; + e_acsl_end_loop11: ; __e_acsl_assert(__gen_e_acsl_forall,(char *)"Postcondition",(char *)"f", (char *)"\\forall integer n;\n 1 < n <= 3 ==> \\old(*(t + n) == 12) && \\old(*(t + (n - 1)) > 5)", 6); diff --git a/src/plugins/e-acsl/tests/gmp/oracle/gen_at_on-purely-logic-variables2.c b/src/plugins/e-acsl/tests/gmp/oracle/gen_at_on-purely-logic-variables2.c index e30789c329d..771df194b25 100644 --- a/src/plugins/e-acsl/tests/gmp/oracle/gen_at_on-purely-logic-variables2.c +++ b/src/plugins/e-acsl/tests/gmp/oracle/gen_at_on-purely-logic-variables2.c @@ -65,6 +65,17 @@ int main(void) __e_acsl_full_init((void *)(& t)); __gen_e_acsl_f(t); g(); + /*@ + assert + ∃ ℤ u; + 10 ≤ u < 20 ∧ + (∃ ℤ v; + -10 < v ≤ -5 + (\let u = -2; u) ∧ + (∃ ℤ w; + 100 < w ≤ 200 ∧ + \at((((n - u) + (\let u = 42; u)) + v) + w > 0,K))); + */ + ; /*@ assert ∃ ℤ j; 2 ≤ j < 10000000000000000 ∧ \at(n + j ≡ 11,L); */ ; diff --git a/src/plugins/e-acsl/translate.ml b/src/plugins/e-acsl/translate.ml index 0597e767c07..4d28939e123 100644 --- a/src/plugins/e-acsl/translate.ml +++ b/src/plugins/e-acsl/translate.ml @@ -1125,7 +1125,8 @@ let named_predicate_to_exp ?name kf env p = named_predicate_to_exp ?name kf env p (* forget optional argument ?rte *) let () = - Quantif.term_to_exp_ref := term_to_exp; + Loops.term_to_exp_ref := term_to_exp; + Loops.translate_named_predicate_ref := translate_named_predicate; Quantif.predicate_to_exp_ref := named_predicate_to_exp; At_with_lscope.term_to_exp_ref := term_to_exp; At_with_lscope.predicate_to_exp_ref := named_predicate_to_exp diff --git a/src/plugins/e-acsl/translate.mli b/src/plugins/e-acsl/translate.mli index 77207f00872..4f8540341fa 100644 --- a/src/plugins/e-acsl/translate.mli +++ b/src/plugins/e-acsl/translate.mli @@ -32,14 +32,14 @@ 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: +val translate_named_predicate: kernel_function -> Env.t -> predicate -> Env.t val translate_rte_annots: - (Format.formatter -> 'a -> unit) -> + (Format.formatter -> 'a -> unit) -> 'a -> - kernel_function -> - Env.t -> + kernel_function -> + Env.t -> code_annotation list -> Env.t -- GitLab