diff --git a/src/kernel_services/abstract_interp/base.ml b/src/kernel_services/abstract_interp/base.ml index 0bfde596c3a5a58f79426bb00d5e24df90604f56..0c7e3ba7eeca445689d0faa9b82e4ac3955e2788 100644 --- a/src/kernel_services/abstract_interp/base.ml +++ b/src/kernel_services/abstract_interp/base.ml @@ -452,6 +452,7 @@ module Base = struct let varname = Datatype.undefined end) let id = id + let pretty_debug = pretty end include Base @@ -549,6 +550,17 @@ let of_string_exp e = module SetLattice = Make_Hashconsed_Lattice_Set(Base)(Hptset) +module BMap = + Hptmap.Make (Base) (Base) (Hptmap.Comp_unused) + (struct let v = [ [] ] end) + (struct let l = [ Ast.self ] end) + +type substitution = base Hptmap.Shape(Base).t + +let substitution_from_list list = + let add map (key, elt) = BMap.add key elt map in + let bmap = List.fold_left add BMap.empty list in + BMap.shape bmap (* Local Variables: diff --git a/src/kernel_services/abstract_interp/base.mli b/src/kernel_services/abstract_interp/base.mli index 708c79c5579a7cd21c2b3a44e64001e47d2cbef7..adbbcbc800ddffd87125846e4e7241daf601803f 100644 --- a/src/kernel_services/abstract_interp/base.mli +++ b/src/kernel_services/abstract_interp/base.mli @@ -225,6 +225,17 @@ val register_memory_var : Cil_types.varinfo -> validity -> t They are created only to fill the contents of another variable. Their field [vsource] is set to false. *) + +(** {2 Substituting bases} + This is used to efficiently replace some bases by others in locations or + in memory states, for instance in {!Locations} or {!Lmap_sig}. *) + +type substitution = base Hptmap.Shape(Base).t +(** Type used for the substitution between bases. *) + +val substitution_from_list: (base * base) list -> substitution +(** Creates a substitution from an association list. *) + (* Local Variables: compile-command: "make -C ../../.." diff --git a/src/kernel_services/abstract_interp/lmap.ml b/src/kernel_services/abstract_interp/lmap.ml index 46906585f7665013e9e5de09741e9e87a4b31377..b2223cda94798f4fd226b56f777c6bb8dfa9e94e 100644 --- a/src/kernel_services/abstract_interp/lmap.ml +++ b/src/kernel_services/abstract_interp/lmap.ml @@ -638,6 +638,14 @@ struct | Top -> Top | Map m -> Map (M.remove b m) + let replace_base shape = function + | Bottom -> Bottom + | Top -> Top + | Map map as t -> + let decide _key = Offsetmap.join in + let modified, map = M.replace_key ~decide shape map in + if modified then Map map else t + let is_reachable = function | Bottom -> false | Top | Map _ -> true diff --git a/src/kernel_services/abstract_interp/lmap_sig.mli b/src/kernel_services/abstract_interp/lmap_sig.mli index 9a7ac8d40b99f7cf4072d0a67e24a5509661db74..f9c31abc77d4b466d0f36735b2c4c8e310e0ee22 100644 --- a/src/kernel_services/abstract_interp/lmap_sig.mli +++ b/src/kernel_services/abstract_interp/lmap_sig.mli @@ -150,6 +150,11 @@ val filter_by_shape: 'a Hptmap.Shape(Base.Base).t -> t -> t (** Removes the base if it is present. Does nothing otherwise. *) val remove_base : Base.t -> t -> t +(** [replace_bases substitition map] replaces some bases in [map] + according to [substitution]. If [substitution] conflates different bases, + the offsetmaps bound to these bases are joined. *) +val replace_base: Base.substitution -> t -> t + (** {2 Iterators} *) diff --git a/src/kernel_services/abstract_interp/locations.ml b/src/kernel_services/abstract_interp/locations.ml index f5c126c7119a38108bfa9d98a3f9b0c2bec5ce0d..442b8d59bc652f8e903e810104b36a7dd8f74640 100644 --- a/src/kernel_services/abstract_interp/locations.ml +++ b/src/kernel_services/abstract_interp/locations.ml @@ -358,6 +358,19 @@ module Location_Bytes = struct | Map _ -> false); true + let replace_base substitution v = + let substitute replace make acc = + let modified, set' = replace substitution acc in + modified, if modified then make set' else v + in + match v with + | Top (Base.SetLattice.Top, _) -> false, v + | Top (Base.SetLattice.Set set, origin) -> + substitute Base.Hptset.replace (inject_top_origin_internal origin) set + | Map map -> + let decide _key = Ival.join in + substitute (M.replace_key ~decide) (fun m -> Map m) map + let overlaps ~partial ~size mm1 mm2 = match mm1, mm2 with | Top _, _ | _, Top _ -> intersects mm1 mm2 diff --git a/src/kernel_services/abstract_interp/locations.mli b/src/kernel_services/abstract_interp/locations.mli index 760e1b93fa61909cf5a2fe0326db8f63f205c7bc..4bea9a7b4e218c9c6ff972577fbfdf18904a6ae4 100644 --- a/src/kernel_services/abstract_interp/locations.mli +++ b/src/kernel_services/abstract_interp/locations.mli @@ -78,6 +78,11 @@ module Location_Bytes : sig (** [add b i loc] binds [b] to [i] in [loc] when [i] is not {!Ival.bottom}, and returns {!bottom} otherwise. *) + val replace_base: Base.substitution -> t -> bool * t + (** [replace_base subst loc] changes the location [loc] by substituting the + pointed bases according to [subst]. If [substitution] conflates different + bases, the offsets bound to these bases are joined. *) + val diff : t -> t -> t (** Over-approximation of difference. [arg2] needs to be exact or an under_approximation. *) diff --git a/src/libraries/utils/hptmap.ml b/src/libraries/utils/hptmap.ml index d7725d945383f676f453e37184198766270b7d05..670978accabdaaddc3d066435e1648dd28eaacac 100644 --- a/src/libraries/utils/hptmap.ml +++ b/src/libraries/utils/hptmap.ml @@ -1131,6 +1131,48 @@ struct let inter_with_shape shape map = merge_with_shape ~inter:true shape map let diff_with_shape shape map = merge_with_shape ~inter:false shape map + (* Intersection and difference between a map and a shape. *) + let partition_with_shape = + let rec merge shape map = + match shape, map with + | Empty, _ -> Empty, map + | _, Empty -> Empty, Empty + | _, Leaf (key, _, _) -> if mem key shape then map, Empty else Empty, map + | Leaf (key, _, _), _ -> begin + try + let v = find key map in + wrap_Leaf key v, remove key map + with Not_found -> Empty, map + end + | Branch (p, m, s0, s1, _), Branch (q, n, t0, t1, _) -> + let rewrap p m u0 u1 = + if t0 == u0 && t1 == u1 then map + else if u0 == Empty then u1 else if u1 == Empty then u0 + else wrap_Branch p m u0 u1 + in + let rewrap_both p m (inter0, diff0) (inter1, diff1) = + rewrap p m inter0 inter1, rewrap p m diff0 diff1 + in + if (p = q) && (m = n) then + (* The trees have the same prefix. Merge their sub-trees. *) + rewrap_both p m (merge s0 t0) (merge s1 t1) + else if (Big_Endian.shorter m n) && (match_prefix q p m) then + (* [q] contains [p]. Merge [map] with a sub-tree of [shape]. *) + if (q land m) = 0 + then merge s0 map + else merge s1 map + else if (Big_Endian.shorter n m) && (match_prefix p q n) then + (* [p] contains [q]. Merge [shape] with a sub-tree of [map]. The other + sub-tree of [map] matches an empty shape. *) + if (p land n) = 0 + then rewrap_both q n (merge shape t0) (Empty, t1) + else rewrap_both q n (Empty, t0) (merge shape t1) + else + (* The prefixes disagree: [map] matches an empty shape. *) + Empty, map + in + merge + let fold2_join_heterogeneous (type arg) (type result) ~cache ~empty_left ~empty_right ~both ~join ~empty = let cache_merge = match cache with | Hptmap_sig.NoCache -> (fun f x y -> f x y) @@ -1302,6 +1344,23 @@ struct in aux + let replace_key ~decide shape map = + let cache = Hptmap_sig.NoCache in + let inter, diff = partition_with_shape shape map in + if is_empty inter + then false, map + else + let join = join ~cache ~symmetric:true ~idempotent:true ~decide in + let both _key value new_key = singleton new_key value in + let new_inter = + fold2_join_heterogeneous + ~cache + ~empty_left:(fun _ -> empty) + ~empty_right:(fun _ -> assert false) + ~empty + ~both ~join inter shape + in + true, join new_inter diff let generic_predicate exn ~cache ~decide_fast ~decide_fst ~decide_snd ~decide_both = if debug_cache then Format.eprintf "CACHE generic_predicate %s@." (fst cache); diff --git a/src/libraries/utils/hptmap_sig.mli b/src/libraries/utils/hptmap_sig.mli index 3fdc7a3eb082e3d848e9b2ef81e695e286b3cc22..c1aa0b93871cff65581819fe777fb173714f50b2 100644 --- a/src/libraries/utils/hptmap_sig.mli +++ b/src/libraries/utils/hptmap_sig.mli @@ -188,6 +188,11 @@ module type S = sig efficient than successive calls to {!remove} or {!add} to build the resulting map. *) + val partition_with_shape: 'a shape -> t -> t * t + (** [partition_with_shape s m] returns two maps [inter, diff] such that: + - [inter] contains the elements of [m] bound in the shape [s]; + - [diff] contains the elements of [m] not bound in the shape [s]. *) + (** {2 Binary predicates} *) type decide_fast = Done | Unknown @@ -343,6 +348,15 @@ module type S = sig called in an unspecified order. The results of the function may be cached, depending on [cache]. *) + val replace_key: decide:(key -> v -> v -> v) -> key shape -> t -> bool * t + (** [replace_key ~decide shape map] substitute keys in [map] according to + [shape]: it returns the [map] in which all bindings from [key] to [v] such + that [key] is bound to [key'] in [shape] are replaced by a binding from + [key'] to [v]. If the new key [key'] was already bound in the map, or if + two keys are replaced by a same key [key'], the [decide] function is used + to compute the final value bound to [key']. + The returned boolean indicates whether the map has been modified: it is + false if the intersection between [shape] and [map] is empty. *) (**/**) (* Undocumented. *) val pretty_debug: Format.formatter -> t -> unit diff --git a/src/libraries/utils/hptset.ml b/src/libraries/utils/hptset.ml index 14afb981d47d767ccf65f6eddc36ba168cb9ac09..0d59892b55fe9aba6db38e25257df9cd95202dfc 100644 --- a/src/libraries/utils/hptset.ml +++ b/src/libraries/utils/hptset.ml @@ -76,6 +76,8 @@ module type S = sig val shape: t -> unit shape val from_shape: 'a shape -> t + val partition_with_shape: 'a shape -> t -> t * t + val fold2_join_heterogeneous: cache:Hptmap_sig.cache_type -> empty_left:('a shape -> 'b) -> @@ -86,6 +88,8 @@ module type S = sig t -> 'a shape -> 'b + val replace: elt shape -> t -> bool * t + val clear_caches: unit -> unit val pretty_debug: t Pretty_utils.formatter @@ -221,6 +225,10 @@ module Make(X: Hptmap.Id_Datatype) let both k () v = both k v in fold2_join_heterogeneous ~cache ~empty_left ~empty_right ~both ~join ~empty + let replace = + let decide _k () () = () in + replace_key ~decide + end (* diff --git a/src/libraries/utils/hptset.mli b/src/libraries/utils/hptset.mli index ad71b75f4834ae4eeb2c2979e52d8c33b4bfc5fd..1da170653c0006277b2111ae767e974ab6a48d41 100644 --- a/src/libraries/utils/hptset.mli +++ b/src/libraries/utils/hptset.mli @@ -88,6 +88,11 @@ module type S = sig val from_shape: 'a shape -> t (** Build a set from another [elt]-indexed map or set. *) + val partition_with_shape: 'a shape -> t -> t * t + (** [partition_with_shape shape set] returns two sets [inter, diff] that are + respectively the intersection and the difference between [set] and + [shape]. *) + val fold2_join_heterogeneous: cache:Hptmap_sig.cache_type -> empty_left:('a shape -> 'b) -> @@ -98,6 +103,11 @@ module type S = sig t -> 'a shape -> 'b + val replace: elt shape -> t -> bool * t + (** [replace shape set] replaces the elements of [set] according to [shape]. + The returned boolean indicates whether the set has been modified; it is + false when the intersection between [shape] and [set] is empty. *) + (** Clear all the caches used internally by the functions of this module. Those caches are not project-aware, so this function must be called at least each a project switch occurs. *) diff --git a/src/plugins/e-acsl/tests/arith/functions_rec.c b/src/plugins/e-acsl/tests/arith/functions_rec.c index 8feb6f4e59dde504eb7ad2e4374c94867e39802a..89eb4a6a15c7c0f242611ebc534fea5aafa09d90 100644 --- a/src/plugins/e-acsl/tests/arith/functions_rec.c +++ b/src/plugins/e-acsl/tests/arith/functions_rec.c @@ -1,6 +1,6 @@ /* run.config_ci COMMENT: recursive logic functions - STDOPT: +"-eva-ignore-recursive-calls" + STDOPT: +"-eva-unroll-recursive-calls 100" */ /*@ logic integer f1(integer n) = diff --git a/src/plugins/e-acsl/tests/arith/longlong.i b/src/plugins/e-acsl/tests/arith/longlong.i index 9be4c44511b20d6b432aee24fd7b92f026d3cd9f..9dc71da4e6dc44fc36bb79c1ed0dd5390cbf0137 100644 --- a/src/plugins/e-acsl/tests/arith/longlong.i +++ b/src/plugins/e-acsl/tests/arith/longlong.i @@ -1,6 +1,6 @@ /* run.config_ci COMMENT: upgrading longlong to GMP - STDOPT: +"-eva-ignore-recursive-calls" + STDOPT: +"-eva-unroll-recursive-calls 8" */ unsigned long long my_pow(unsigned int x, unsigned int n) { diff --git a/src/plugins/e-acsl/tests/arith/oracle_ci/functions_rec.res.oracle b/src/plugins/e-acsl/tests/arith/oracle_ci/functions_rec.res.oracle index 490eda1facc8ddd5e0b0ea133de1d4f871d3e14f..a30ec62a8b4a0a1fc14312fac9b2ef01ef5888c9 100644 --- a/src/plugins/e-acsl/tests/arith/oracle_ci/functions_rec.res.oracle +++ b/src/plugins/e-acsl/tests/arith/oracle_ci/functions_rec.res.oracle @@ -8,80 +8,13 @@ function __e_acsl_assert, behavior blocking: precondition got status unknown. [eva:alarm] tests/arith/functions_rec.c:23: Warning: assertion got status unknown. -[eva] tests/arith/functions_rec.c:7: Warning: - recursive call during value analysis - of __gen_e_acsl_f1_2 (__gen_e_acsl_f1_2 <- __gen_e_acsl_f1_2 :: tests/arith/functions_rec.c:7 <- - __gen_e_acsl_f1 :: tests/arith/functions_rec.c:24 <- - main). - Assuming the call has no effect. The analysis will be unsound. [eva:alarm] tests/arith/functions_rec.c:24: Warning: function __e_acsl_assert, behavior blocking: precondition got status unknown. [eva:alarm] tests/arith/functions_rec.c:24: Warning: assertion got status unknown. -[eva] tests/arith/functions_rec.c:10: Warning: - recursive call during value analysis - of __gen_e_acsl_f2_2 (__gen_e_acsl_f2_2 <- __gen_e_acsl_f2_2 :: tests/arith/functions_rec.c:10 <- - __gen_e_acsl_f2 :: tests/arith/functions_rec.c:26 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva] tests/arith/functions_rec.c:10: Warning: - recursive call during value analysis - of __gen_e_acsl_f2_2 (__gen_e_acsl_f2_2 <- __gen_e_acsl_f2_2 :: tests/arith/functions_rec.c:10 <- - __gen_e_acsl_f2 :: tests/arith/functions_rec.c:26 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva] tests/arith/functions_rec.c:10: Warning: - recursive call during value analysis - of __gen_e_acsl_f2_2 (__gen_e_acsl_f2_2 <- __gen_e_acsl_f2_2 :: tests/arith/functions_rec.c:10 <- - __gen_e_acsl_f2 :: tests/arith/functions_rec.c:26 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva:alarm] tests/arith/functions_rec.c:10: Warning: - function __e_acsl_assert, behavior blocking: precondition got status unknown. -[eva:alarm] tests/arith/functions_rec.c:10: Warning: - division by zero. assert __gen_e_acsl_f2_8 ≢ 0; -[eva:alarm] tests/arith/functions_rec.c:10: Warning: - signed overflow. - assert -2147483648 ≤ __gen_e_acsl_f2_4 * __gen_e_acsl_f2_6; -[eva:alarm] tests/arith/functions_rec.c:10: Warning: - signed overflow. assert __gen_e_acsl_f2_4 * __gen_e_acsl_f2_6 ≤ 2147483647; -[eva:alarm] tests/arith/functions_rec.c:10: Warning: - signed overflow. - assert - (int)(__gen_e_acsl_f2_4 * __gen_e_acsl_f2_6) / __gen_e_acsl_f2_8 ≤ - 2147483647; -[eva:alarm] tests/arith/functions_rec.c:10: Warning: - division by zero. assert __gen_e_acsl_f2_13 ≢ 0; -[eva:alarm] tests/arith/functions_rec.c:10: Warning: - signed overflow. - assert -2147483648 ≤ __gen_e_acsl_f2_9 * __gen_e_acsl_f2_11; -[eva:alarm] tests/arith/functions_rec.c:10: Warning: - signed overflow. - assert __gen_e_acsl_f2_9 * __gen_e_acsl_f2_11 ≤ 2147483647; -[eva:alarm] tests/arith/functions_rec.c:10: Warning: - signed overflow. - assert - (int)(__gen_e_acsl_f2_9 * __gen_e_acsl_f2_11) / __gen_e_acsl_f2_13 ≤ - 2147483647; -[eva:alarm] tests/arith/functions_rec.c:26: Warning: - function __e_acsl_assert, behavior blocking: precondition got status unknown. [eva:alarm] tests/arith/functions_rec.c:26: Warning: assertion got status unknown. -[eva] tests/arith/functions_rec.c:14: Warning: - recursive call during value analysis - of __gen_e_acsl_f3_2 (__gen_e_acsl_f3_2 <- __gen_e_acsl_f3_2 :: tests/arith/functions_rec.c:14 <- - __gen_e_acsl_f3 :: tests/arith/functions_rec.c:28 <- - main). - Assuming the call has no effect. The analysis will be unsound. [eva:alarm] tests/arith/functions_rec.c:28: Warning: assertion got status unknown. -[eva] tests/arith/functions_rec.c:17: Warning: - recursive call during value analysis - of __gen_e_acsl_f4_2 (__gen_e_acsl_f4_2 <- __gen_e_acsl_f4_2 :: tests/arith/functions_rec.c:17 <- - __gen_e_acsl_f4 :: tests/arith/functions_rec.c:30 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva:alarm] tests/arith/functions_rec.c:30: Warning: - function __e_acsl_assert, behavior blocking: precondition got status unknown. [eva:alarm] tests/arith/functions_rec.c:30: Warning: assertion got status unknown. diff --git a/src/plugins/e-acsl/tests/arith/oracle_ci/gen_functions_rec.c b/src/plugins/e-acsl/tests/arith/oracle_ci/gen_functions_rec.c index fc96bb91d0626f1828b71d3eb12c44e8ef57f99f..b766248de7c8fd4d07f231228583ebb240bd00a3 100644 --- a/src/plugins/e-acsl/tests/arith/oracle_ci/gen_functions_rec.c +++ b/src/plugins/e-acsl/tests/arith/oracle_ci/gen_functions_rec.c @@ -183,20 +183,6 @@ int __gen_e_acsl_f2(int n) __e_acsl_assert(__gen_e_acsl_f2_13 != 0,1,"RTE","f2", "division_by_zero: __gen_e_acsl_f2_13 != 0", "tests/arith/functions_rec.c",10); - /*@ assert Eva: division_by_zero: __gen_e_acsl_f2_13 ≢ 0; */ - /*@ assert - Eva: signed_overflow: - -2147483648 ≤ __gen_e_acsl_f2_9 * __gen_e_acsl_f2_11; - */ - /*@ assert - Eva: signed_overflow: - __gen_e_acsl_f2_9 * __gen_e_acsl_f2_11 ≤ 2147483647; - */ - /*@ assert - Eva: signed_overflow: - (int)(__gen_e_acsl_f2_9 * __gen_e_acsl_f2_11) / __gen_e_acsl_f2_13 - ≤ 2147483647; - */ __gen_e_acsl_if_4 = (__gen_e_acsl_f2_9 * __gen_e_acsl_f2_11) / __gen_e_acsl_f2_13; } return __gen_e_acsl_if_4; @@ -216,20 +202,6 @@ int __gen_e_acsl_f2_2(long n) __e_acsl_assert(__gen_e_acsl_f2_8 != 0,1,"RTE","f2_2", "division_by_zero: __gen_e_acsl_f2_8 != 0", "tests/arith/functions_rec.c",10); - /*@ assert Eva: division_by_zero: __gen_e_acsl_f2_8 ≢ 0; */ - /*@ assert - Eva: signed_overflow: - -2147483648 ≤ __gen_e_acsl_f2_4 * __gen_e_acsl_f2_6; - */ - /*@ assert - Eva: signed_overflow: - __gen_e_acsl_f2_4 * __gen_e_acsl_f2_6 ≤ 2147483647; - */ - /*@ assert - Eva: signed_overflow: - (int)(__gen_e_acsl_f2_4 * __gen_e_acsl_f2_6) / __gen_e_acsl_f2_8 - ≤ 2147483647; - */ __gen_e_acsl_if_3 = (__gen_e_acsl_f2_4 * __gen_e_acsl_f2_6) / __gen_e_acsl_f2_8; } return __gen_e_acsl_if_3; diff --git a/src/plugins/e-acsl/tests/arith/oracle_ci/gen_longlong.c b/src/plugins/e-acsl/tests/arith/oracle_ci/gen_longlong.c index 015b45a630e6b6006768996e99dccb81acf5910e..21f7073ae453abd87367cfa6774390b8b8e87753 100644 --- a/src/plugins/e-acsl/tests/arith/oracle_ci/gen_longlong.c +++ b/src/plugins/e-acsl/tests/arith/oracle_ci/gen_longlong.c @@ -12,8 +12,6 @@ unsigned long long my_pow(unsigned int x, unsigned int n) } tmp_0 = my_pow(x,n / (unsigned int)2); tmp = (int)tmp_0; - /*@ assert Eva: signed_overflow: -2147483648 ≤ tmp * tmp; */ - /*@ assert Eva: signed_overflow: tmp * tmp ≤ 2147483647; */ tmp *= tmp; if (n % (unsigned int)2 == (unsigned int)0) { __retres = (unsigned long long)tmp; diff --git a/src/plugins/e-acsl/tests/arith/oracle_ci/longlong.res.oracle b/src/plugins/e-acsl/tests/arith/oracle_ci/longlong.res.oracle index a8d7dc220ee03e4929c36d12d7a5bd8e329e52dd..36e0f42013b7f8302a598494fa5d342a8b7a2b7e 100644 --- a/src/plugins/e-acsl/tests/arith/oracle_ci/longlong.res.oracle +++ b/src/plugins/e-acsl/tests/arith/oracle_ci/longlong.res.oracle @@ -1,13 +1,5 @@ [e-acsl] beginning translation. [e-acsl] translation done in project "e-acsl". -[eva] tests/arith/longlong.i:9: Warning: - recursive call during value analysis - of my_pow (my_pow <- my_pow :: tests/arith/longlong.i:16 <- main). Assuming - the call has no effect. The analysis will be unsound. -[eva:alarm] tests/arith/longlong.i:10: Warning: - signed overflow. assert -2147483648 ≤ tmp * tmp; -[eva:alarm] tests/arith/longlong.i:10: Warning: - signed overflow. assert tmp * tmp ≤ 2147483647; [eva:alarm] tests/arith/longlong.i:17: Warning: function __gmpz_import: precondition got status unknown. [eva:alarm] tests/arith/longlong.i:17: Warning: diff --git a/src/plugins/e-acsl/tests/bts/bts1395.i b/src/plugins/e-acsl/tests/bts/bts1395.i index ef01c83d78b3a55f12e943321f73fdc7567fe102..34b85b1ee8c73ac93cbf2eb25dde331690ad4ab0 100644 --- a/src/plugins/e-acsl/tests/bts/bts1395.i +++ b/src/plugins/e-acsl/tests/bts/bts1395.i @@ -1,6 +1,6 @@ /* run.config_ci COMMENT: recursive function - STDOPT: +"-eva-ignore-recursive-calls" + STDOPT: +"-eva-unroll-recursive-calls 5" */ /*@ requires n > 0; */ diff --git a/src/plugins/e-acsl/tests/bts/oracle_ci/bts1395.res.oracle b/src/plugins/e-acsl/tests/bts/oracle_ci/bts1395.res.oracle index 30c8d8ed4cd52200784001e557b21efd970c070b..efd026311297e55d8fefb674326118e6ece88624 100644 --- a/src/plugins/e-acsl/tests/bts/oracle_ci/bts1395.res.oracle +++ b/src/plugins/e-acsl/tests/bts/oracle_ci/bts1395.res.oracle @@ -1,16 +1,2 @@ [e-acsl] beginning translation. [e-acsl] translation done in project "e-acsl". -[eva] tests/bts/bts1395.i:9: Warning: - recursive call during value analysis - of __gen_e_acsl_fact (__gen_e_acsl_fact <- fact :: tests/bts/bts1395.i:7 <- - __gen_e_acsl_fact :: tests/bts/bts1395.i:13 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva:alarm] tests/bts/bts1395.i:9: Warning: - signed overflow. assert -2147483648 ≤ n * tmp; - (tmp from fact(n - 1)) -[eva:alarm] tests/bts/bts1395.i:9: Warning: - signed overflow. assert n * tmp ≤ 2147483647; - (tmp from fact(n - 1)) -[eva:alarm] tests/bts/bts1395.i:14: Warning: - function __e_acsl_assert, behavior blocking: precondition got status unknown. diff --git a/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1395.c b/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1395.c index 1e95f4093d1686374aeefee4b482a76c9516c257..7ffe91bbde5d7c8b8cc2d47711157452d4ab25d5 100644 --- a/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1395.c +++ b/src/plugins/e-acsl/tests/bts/oracle_ci/gen_bts1395.c @@ -16,8 +16,6 @@ int fact(int n) } tmp = __gen_e_acsl_fact(n - 1); ; - /*@ assert Eva: signed_overflow: -2147483648 ≤ n * tmp; */ - /*@ assert Eva: signed_overflow: n * tmp ≤ 2147483647; */ __retres = n * tmp; return_label: return __retres; } diff --git a/src/plugins/e-acsl/tests/constructs/decrease.i b/src/plugins/e-acsl/tests/constructs/decrease.i index b5dc3a50ca7515eb3f4fa32bcff259c351083bce..569bcb71d0f339ffec25afb1935e3da6e30b0053 100644 --- a/src/plugins/e-acsl/tests/constructs/decrease.i +++ b/src/plugins/e-acsl/tests/constructs/decrease.i @@ -1,5 +1,5 @@ /* run.config_ci, run.config_dev - STDOPT: +"-eva-ignore-recursive-calls -eva-slevel 7" + STDOPT: +"-eva-unroll-recursive-calls 10 -eva-slevel 7" */ // Test that the last iteration of the variant can be negative diff --git a/src/plugins/e-acsl/tests/constructs/oracle_ci/decrease.res.oracle b/src/plugins/e-acsl/tests/constructs/oracle_ci/decrease.res.oracle index 74f4f63423966d0396e43ebbb9a02c8887c3ddcf..2a909408ab28551a31c8128f578c384ab0e246df 100644 --- a/src/plugins/e-acsl/tests/constructs/oracle_ci/decrease.res.oracle +++ b/src/plugins/e-acsl/tests/constructs/oracle_ci/decrease.res.oracle @@ -9,65 +9,3 @@ E-ACSL construct `decreases clause' is not yet supported. Ignoring annotation. [e-acsl] translation done in project "e-acsl". -[eva] tests/constructs/decrease.i:43: Warning: - recursive call during value analysis - of __gen_e_acsl_fib (__gen_e_acsl_fib <- fib :: tests/constructs/decrease.i:40 <- - __gen_e_acsl_fib :: tests/constructs/decrease.i:74 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva] tests/constructs/decrease.i:43: Warning: - recursive call during value analysis - of __gen_e_acsl_fib (__gen_e_acsl_fib <- fib :: tests/constructs/decrease.i:40 <- - __gen_e_acsl_fib :: tests/constructs/decrease.i:74 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva:alarm] tests/constructs/decrease.i:43: Warning: - signed overflow. - assert -2147483648 ≤ tmp + tmp_0; - (tmp from fib(n - 1), tmp_0 from fib(n - 2)) -[eva:alarm] tests/constructs/decrease.i:43: Warning: - signed overflow. - assert tmp + tmp_0 ≤ 2147483647; - (tmp from fib(n - 1), tmp_0 from fib(n - 2)) -[eva:alarm] tests/constructs/decrease.i:75: Warning: - function __e_acsl_assert, behavior blocking: precondition got status unknown. -[eva] tests/constructs/decrease.i:58: Warning: - recursive call during value analysis - of __gen_e_acsl_even (__gen_e_acsl_even <- odd :: tests/constructs/decrease.i:47 <- - __gen_e_acsl_odd :: tests/constructs/decrease.i:52 <- - even :: tests/constructs/decrease.i:50 <- - __gen_e_acsl_even :: tests/constructs/decrease.i:77 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva:alarm] tests/constructs/decrease.i:78: Warning: - function __e_acsl_assert, behavior blocking: precondition got status unknown. -[eva] tests/constructs/decrease.i:58: Warning: - recursive call during value analysis - of __gen_e_acsl_even (__gen_e_acsl_even <- odd :: tests/constructs/decrease.i:47 <- - __gen_e_acsl_odd :: tests/constructs/decrease.i:52 <- - even :: tests/constructs/decrease.i:50 <- - __gen_e_acsl_even :: tests/constructs/decrease.i:79 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva:alarm] tests/constructs/decrease.i:80: Warning: - function __e_acsl_assert, behavior blocking: precondition got status unknown. -[eva] tests/constructs/decrease.i:52: Warning: - recursive call during value analysis - of __gen_e_acsl_odd (__gen_e_acsl_odd <- even :: tests/constructs/decrease.i:50 <- - __gen_e_acsl_even :: tests/constructs/decrease.i:58 <- - odd :: tests/constructs/decrease.i:47 <- - __gen_e_acsl_odd :: tests/constructs/decrease.i:81 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva:alarm] tests/constructs/decrease.i:82: Warning: - function __e_acsl_assert, behavior blocking: precondition got status unknown. -[eva] tests/constructs/decrease.i:52: Warning: - recursive call during value analysis - of __gen_e_acsl_odd (__gen_e_acsl_odd <- even :: tests/constructs/decrease.i:50 <- - __gen_e_acsl_even :: tests/constructs/decrease.i:58 <- - odd :: tests/constructs/decrease.i:47 <- - __gen_e_acsl_odd :: tests/constructs/decrease.i:83 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva:alarm] tests/constructs/decrease.i:84: Warning: - function __e_acsl_assert, behavior blocking: precondition got status unknown. diff --git a/src/plugins/e-acsl/tests/constructs/oracle_ci/gen_decrease.c b/src/plugins/e-acsl/tests/constructs/oracle_ci/gen_decrease.c index 41a66ca7b5efb2a1f491aca7a9eefbe396862a59..116816df289b37cce0dcf9fe63c4b5fe6b748abf 100644 --- a/src/plugins/e-acsl/tests/constructs/oracle_ci/gen_decrease.c +++ b/src/plugins/e-acsl/tests/constructs/oracle_ci/gen_decrease.c @@ -87,8 +87,6 @@ int fib(int n) } tmp = __gen_e_acsl_fib(n - 1); tmp_0 = __gen_e_acsl_fib(n - 2); - /*@ assert Eva: signed_overflow: -2147483648 ≤ tmp + tmp_0; */ - /*@ assert Eva: signed_overflow: tmp + tmp_0 ≤ 2147483647; */ __retres = tmp + tmp_0; return_label: return __retres; } diff --git a/src/plugins/value/domains/abstract_domain.mli b/src/plugins/value/domains/abstract_domain.mli index a667687b8c603e5f9a1c51a5c2d30d39fde832ba..7c5861aa9420ac2df98b4be9602488d1d5e27355 100644 --- a/src/plugins/value/domains/abstract_domain.mli +++ b/src/plugins/value/domains/abstract_domain.mli @@ -251,16 +251,27 @@ module type Transfer = sig stmt -> exp -> bool -> (value, location, origin) valuation -> state -> state or_bottom - (** [start_call stmt call valuation state] returns an initial state + (** [start_call stmt call recursion valuation state] returns an initial state for the analysis of a called function. In particular, this function should introduce the formal parameters in the state, if necessary. - [stmt] is the statement of the call site; - [call] represents the call: the called function and the arguments; + - [recursion] is the information needed to interpret a recursive call. + It is None if the call is not recursive. - [state] is the abstract state at the call site, before the call; - [valuation] is a cache for all values and locations computed during - the evaluation of the function and its arguments. *) + the evaluation of the function and its arguments. + + On recursive calls, [recursion] contains some substitution of variables + to be applied on the domain state to prevent mixing up local variables + and formal parameters of different recursive calls. + See {!Eval.recursion} for more details. + This substitution has been applied on values and expressions in [call], + but not in the [valuation] given as argument. If the domain uses some + information from the [valuation] on a recursive call, it must apply the + substitution on it. *) val start_call: - stmt -> (location, value) call -> + stmt -> (location, value) call -> recursion option -> (value, location, origin) valuation -> state -> state or_bottom (** [finalize_call stmt call ~pre ~post] computes the state after a function @@ -268,10 +279,13 @@ module type Transfer = sig end of the called function. - [stmt] is the statement of the call site; - [call] represents the function call and its arguments. + - [recursion] is the information needed to interpret a recursive call. + It is None if the call is not recursive. - [pre] and [post] are the states before and at the end of the call respectively. *) val finalize_call: - stmt -> (location, value) call -> pre:state -> post:state -> state or_bottom + stmt -> (location, value) call -> recursion option -> + pre:state -> post:state -> state or_bottom (** Called on the Frama_C_show_each directives. Prints the internal properties inferred by the domain in the [state] about the expression [exp]. Can use diff --git a/src/plugins/value/domains/apron/apron_domain.ml b/src/plugins/value/domains/apron/apron_domain.ml index 9c2d3e85184dd5ab65a9e17762df7bb46f081255..9bfd7edafd34c312d3b529bd2ec54e7ce0b3c197 100644 --- a/src/plugins/value/domains/apron/apron_domain.ml +++ b/src/plugins/value/domains/apron/apron_domain.ml @@ -634,7 +634,11 @@ module Make (Man : Input) = struct with | Out_of_Scope _ -> `Value state - let start_call _stmt call valuation state = + let start_call _stmt call recursion valuation state = + if recursion <> None + then + Value_parameters.abort ~current:true + "The binding to APRON domains does not support recursive calls."; update valuation state >>- fun state -> let eval = make_eval state in let oracle = make_oracle valuation in @@ -669,7 +673,7 @@ module Make (Man : Input) = struct then `Bottom else `Value state - let finalize_call _stmt _call ~pre:_ ~post = `Value post + let finalize_call _stmt _call _recursion ~pre:_ ~post = `Value post let show_expr _valuation _state _fmt _expr = () diff --git a/src/plugins/value/domains/cvalue/cvalue_domain.ml b/src/plugins/value/domains/cvalue/cvalue_domain.ml index 661b972b1ad7cc1f53fefcd7a1541b11d16f2aa4..80f885d59365f5a7cc965285394b602cf60d6a7e 100644 --- a/src/plugins/value/domains/cvalue/cvalue_domain.ml +++ b/src/plugins/value/domains/cvalue/cvalue_domain.ml @@ -230,15 +230,53 @@ module State = struct Cvalue_transfer.assume stmt expr positive valuation s >>-: fun s -> s, clob - let start_call stmt call valuation (s, _clob) = - Cvalue_transfer.start_call stmt call valuation s >>-: fun state -> - state, Locals_scoping.bottom () - - let finalize_call stmt call ~pre ~post = - let (post_state, post_clob) = post - and pre_state, clob = pre in + let is_direct_recursion stmt call = + try + let kf = Kernel_function.find_englobing_kf stmt in + Kernel_function.equal kf call.kf + with Not_found -> false (* Should not happen *) + + let start_recursive_call stmt call recursion (state, clob) = + let direct = is_direct_recursion stmt call in + let state = Model.remove_variables recursion.withdrawal state in + let substitution = recursion.base_substitution in + let clob = if direct then clob else Locals_scoping.top () in + let state = Locals_scoping.substitute substitution clob state in + Model.replace_base substitution state + + let start_call stmt call recursion valuation (state, clob) = + (* Uses the [valuation] to update the [state] before the substitution + for recursive calls. *) + Cvalue_transfer.update valuation state >>- fun state -> + let state = + match recursion with + | None -> state + | Some recursion -> start_recursive_call stmt call recursion (state, clob) + in + Cvalue_transfer.start_call stmt call recursion valuation state + >>-: fun state -> state, Locals_scoping.bottom () + + let finalize_recursive_call stmt call ~pre recursion state = + let direct = is_direct_recursion stmt call in + let pre, clob = pre in + let substitution = recursion.base_substitution in + let state = Model.replace_base substitution state in + let clob = if direct then clob else Locals_scoping.top () in + let state = Locals_scoping.substitute substitution clob state in + let shape = Base.Hptset.shape recursion.base_withdrawal in + let inter = Cvalue.Model.filter_by_shape shape pre in + Cvalue.Model.merge ~into:state inter + + let finalize_call stmt call recursion ~pre ~post = + let (pre, clob) = pre in + let (post, post_clob) = post in Locals_scoping.(remember_bases_with_locals clob post_clob.clob); - Cvalue_transfer.finalize_call stmt call ~pre:pre_state ~post:post_state + let post = + Extlib.opt_fold + (finalize_recursive_call stmt call ~pre:(pre, clob)) + recursion post + in + Cvalue_transfer.finalize_call stmt call recursion ~pre ~post >>-: fun state -> state, clob diff --git a/src/plugins/value/domains/cvalue/cvalue_transfer.ml b/src/plugins/value/domains/cvalue/cvalue_transfer.ml index 1f2c66726233a8357c3b4bb193f38263caafd06b..26518aa8d7c76a6a249d3c082b9131c453b4bbda 100644 --- a/src/plugins/value/domains/cvalue/cvalue_transfer.ml +++ b/src/plugins/value/domains/cvalue/cvalue_transfer.ml @@ -204,14 +204,13 @@ let actualize_formals state arguments = in List.fold_left treat_one_formal state arguments -let start_call _stmt call valuation state = - let state = update valuation state in +let start_call _stmt call _recursion _valuation state = let with_formals = actualize_formals state call.arguments in let stack_with_call = Value_util.call_stack () in Db.Value.Call_Value_Callbacks.apply (with_formals, stack_with_call); `Value with_formals -let finalize_call stmt call ~pre:_ ~post:state = +let finalize_call stmt call _recursion ~pre:_ ~post:state = (* Deallocate memory allocated via alloca(). To minimize computations, only do it for function definitions. *) let state' = diff --git a/src/plugins/value/domains/cvalue/locals_scoping.ml b/src/plugins/value/domains/cvalue/locals_scoping.ml index 4dd0181e5d2bd153c4455415880c1b1b4b9e1826..9fc5b4d5deedf494e21a35cffe5fed9f5997aa1e 100644 --- a/src/plugins/value/domains/cvalue/locals_scoping.ml +++ b/src/plugins/value/domains/cvalue/locals_scoping.ml @@ -127,6 +127,31 @@ let make_escaping_fundec fundec clob vars state = in make_escaping ~exact:true ~escaping ~on_escaping ~within:clob.clob state +let substitute substitution clob state = + (* Apply the [substitution] to [offsm]. If it is modified, bind the new + offsetmap to [base] in [state], and add the [base] to [set]. *) + let replace_offsm base offsm state = + let f v = snd (Cvalue.V_Or_Uninitialized.replace_base substitution v) in + let offsm' = Cvalue.V_Offsetmap.map_on_values f offsm in + if Cvalue.V_Offsetmap.equal offsm' offsm + then state + else Cvalue.Model.add_base base offsm' state + in + (* Apply the substitution to the offsetmap bound to [base] in [state] *) + let replace_base base acc = + match Cvalue.Model.find_base base state with + | `Value offsm -> replace_offsm base offsm acc + | `Top | `Bottom -> acc + | exception Not_found -> acc + in + (* Iterate on all the bases that might contain a variable to substitute *) + try Base.SetLattice.fold replace_base clob.clob (replace_base Base.null state) + with Abstract_interp.Error_Top -> + (* [clob] is too imprecise. Iterate on the entire memory state instead, + which is much slower. *) + match state with + | Cvalue.Model.Top | Cvalue.Model.Bottom -> state + | Cvalue.Model.Map map -> Cvalue.Model.fold replace_offsm map state (* Local Variables: diff --git a/src/plugins/value/domains/cvalue/locals_scoping.mli b/src/plugins/value/domains/cvalue/locals_scoping.mli index bc78ce6973d84ed9fd0ff586c7612cd468ac2104..64cdf339a39ceacca0dd271eb12b6c2eea56da7d 100644 --- a/src/plugins/value/domains/cvalue/locals_scoping.mli +++ b/src/plugins/value/domains/cvalue/locals_scoping.mli @@ -70,6 +70,10 @@ val make_escaping_fundec: [fdec] is used to detect whether we are deallocating the outer scope of a function, in which case a different warning is emitted. *) +val substitute: + Base.substitution -> clobbered_set -> Cvalue.Model.t -> Cvalue.Model.t +(** [substitute substitution clob state] applies [substitution] to all pointer + values in the offsetmaps bound to variables in [clob] in [state]. *) (* Local Variables: diff --git a/src/plugins/value/domains/domain_builder.ml b/src/plugins/value/domains/domain_builder.ml index f19b48efa1217c95f8d54bc13b5930e2a7e4e2f0..0c5e09da764e81ee6ed1bd33f195255a9ed31e96 100644 --- a/src/plugins/value/domains/domain_builder.ml +++ b/src/plugins/value/domains/domain_builder.ml @@ -48,8 +48,7 @@ let simplify_call call = { kf = call.Eval.kf; arguments = List.map simplify_argument call.Eval.arguments; rest = List.map fst call.Eval.rest; - return = call.Eval.return; - recursive = call.Eval.recursive } + return = call.Eval.return; } module Make_Minimal (Value: Abstract_value.S) @@ -82,10 +81,16 @@ module Make_Minimal let assume stmt expr positive _valuation state = Domain.assume stmt expr positive state - let start_call stmt call _valuation state = - `Value (Domain.start_call stmt (simplify_call call) state) + let start_call stmt call recursion _valuation state = + match recursion with + | None -> `Value (Domain.start_call stmt (simplify_call call) state) + | Some _ -> + (* TODO *) + Value_parameters.abort + "The domain %s does not support recursive call." Domain.name - let finalize_call stmt call ~pre ~post = + let finalize_call stmt call recursion ~pre ~post = + assert (recursion = None); Domain.finalize_call stmt (simplify_call call) ~pre ~post let show_expr _valuation = Domain.show_expr @@ -218,9 +223,18 @@ module Complete_Simple_Cvalue (Domain: Simpler_domains.Simple_Cvalue) Domain.assign kinstr lv expr value (record valuation) state let assume stmt expr positive valuation state = Domain.assume stmt expr positive (record valuation) state - let start_call stmt call valuation state = - `Value (Domain.start_call stmt call (record valuation) state) - let finalize_call = Domain.finalize_call + + let start_call stmt call recursion valuation state = + match recursion with + | None -> `Value (Domain.start_call stmt call (record valuation) state) + | Some _ -> + (* TODO *) + Value_parameters.abort + "The domain %s does not support recursive call." Domain.name + + let finalize_call stmt call recursion = + assert (recursion = None); + Domain.finalize_call stmt call let show_expr _valuation = Domain.show_expr @@ -436,7 +450,7 @@ module Restrict - otherwise, only propagate the state from the call site to kill the properties that depend on locations written in the called functions. *) - let start_call stmt call valuation state = + let start_call stmt call recursion valuation state = (* Starts the call with mode [new_mode]. [previous_mode] is the current mode of the caller. *) let start_call_with_mode ?previous_mode ~new_mode state = @@ -444,7 +458,7 @@ module Restrict then match previous_mode with | Some mode when mode.current.write -> - Domain.start_call stmt call valuation state >>-: fun state -> + Domain.start_call stmt call recursion valuation state >>-: fun state -> Some (state, new_mode) | _ -> `Value (Some (start_analysis call state, new_mode)) @@ -465,13 +479,13 @@ module Restrict | None, None -> `Value None - let finalize_call stmt call ~pre ~post = + let finalize_call stmt call recursion ~pre ~post = match pre, post with | None, _ | _, None -> `Value None | Some (pre, pre_mode), Some (post, post_mode) -> if post_mode.current.write then - Domain.finalize_call stmt call ~pre ~post >>-: fun state -> + Domain.finalize_call stmt call recursion ~pre ~post >>-: fun state -> Some (state, pre_mode) else `Value (Some (post, pre_mode)) diff --git a/src/plugins/value/domains/domain_lift.ml b/src/plugins/value/domains/domain_lift.ml index 0ff4608c1cdc1bead64778c44b3c8d7d4fe61646..63fe0d3bdf20aea816374463d3a0df398431fafc 100644 --- a/src/plugins/value/domains/domain_lift.ml +++ b/src/plugins/value/domains/domain_lift.ml @@ -116,11 +116,12 @@ module Make let assume stmt expr positive valuation state = Domain.assume stmt expr positive (lift_valuation valuation) state - let start_call stmt call valuation state = - Domain.start_call stmt (lift_call call) (lift_valuation valuation) state + let start_call stmt call recursion valuation state = + Domain.start_call + stmt (lift_call call) recursion (lift_valuation valuation) state - let finalize_call stmt call ~pre ~post = - Domain.finalize_call stmt (lift_call call) ~pre ~post + let finalize_call stmt call recursion ~pre ~post = + Domain.finalize_call stmt (lift_call call) recursion ~pre ~post let show_expr valuation = Domain.show_expr (lift_valuation valuation) diff --git a/src/plugins/value/domains/domain_product.ml b/src/plugins/value/domains/domain_product.ml index 683892ef2dcc07bd5da22c1a3834d06a3437447a..4ea88b8b41f51be54b2ec089efb36e4f948599ed 100644 --- a/src/plugins/value/domains/domain_product.ml +++ b/src/plugins/value/domains/domain_product.ml @@ -155,18 +155,20 @@ module Make Right.assume stmt expr positive (right_val valuation) right >>-: fun right -> left, right - let finalize_call stmt call ~pre ~post = + let finalize_call stmt call recursion ~pre ~post = let pre_left, pre_right = pre and left_state, right_state = post in - Left.finalize_call stmt call ~pre:pre_left ~post:left_state + Left.finalize_call stmt call recursion ~pre:pre_left ~post:left_state >>- fun left -> - Right.finalize_call stmt call ~pre:pre_right ~post:right_state + Right.finalize_call stmt call recursion ~pre:pre_right ~post:right_state >>-: fun right -> left, right - let start_call stmt call valuation (left, right) = - Left.start_call stmt call (left_val valuation) left >>- fun left -> - Right.start_call stmt call (right_val valuation) right >>-: fun right -> + let start_call stmt call recursion valuation (left, right) = + Left.start_call stmt call recursion (left_val valuation) left + >>- fun left -> + Right.start_call stmt call recursion (right_val valuation) right + >>-: fun right -> left, right let show_expr = diff --git a/src/plugins/value/domains/equality/equality_domain.ml b/src/plugins/value/domains/equality/equality_domain.ml index 2849ec1f6f3181dc30a8be6536f26c0df68c57c9..74925890fdce72eaba7ab228afc9f19b2cfe097f 100644 --- a/src/plugins/value/domains/equality/equality_domain.ml +++ b/src/plugins/value/domains/equality/equality_domain.ml @@ -473,16 +473,28 @@ module Make end | _ -> `Value state - let start_call _stmt call valuation state = + let start_recursive_call recursion state = + let vars = List.map fst recursion.substitution @ recursion.withdrawal in + unscope state vars + + let start_call _stmt call recursion valuation state = let state = - match call_init_state call.kf with - | ISCaller -> assign_formals valuation call state - | ISFormals -> assign_formals valuation call empty - | ISEmpty -> empty + match recursion with + | Some recursion -> + (* No relation inferred from the assignment of formal parameters + for recursive calls, because the valuation cannot be used safely + as the substitution of local and formals variables has not been + applied to it. *) + start_recursive_call recursion state + | None -> + match call_init_state call.kf with + | ISCaller -> assign_formals valuation call state + | ISFormals -> assign_formals valuation call empty + | ISEmpty -> empty in `Value state - let finalize_call _stmt call ~pre ~post = + let finalize_call _stmt call _recursion ~pre ~post = if call_init_state call.kf = ISCaller then `Value post (* [pre] was the state inferred in the caller, and it has been updated during the analysis of [kf] into diff --git a/src/plugins/value/domains/gauges/gauges_domain.ml b/src/plugins/value/domains/gauges/gauges_domain.ml index 00641adb100e2b346ca8c8de13da269f824c713e..23cef9f01a25a84154166592159a41ad9281d01c 100644 --- a/src/plugins/value/domains/gauges/gauges_domain.ml +++ b/src/plugins/value/domains/gauges/gauges_domain.ml @@ -1208,7 +1208,7 @@ module D_Impl : Abstract_domain.S try `Value (G.assign to_loc to_val lv.lval e state) with Unassignable -> `Value (kill lv.lloc state) - let finalize_call _stmt _call ~pre ~post = + let finalize_call _stmt _call _recursion ~pre ~post = let state = match function_calls_handling with | FullInterprocedural -> post @@ -1217,10 +1217,16 @@ module D_Impl : Abstract_domain.S in `Value state - let start_call _stmt call valuation state = + let start_recursive_call recursion state = + let vars = List.map fst recursion.substitution @ recursion.withdrawal in + remove_variables vars state + + let start_call _stmt call recursion valuation state = let state = match function_calls_handling with - | FullInterprocedural -> update valuation state + | FullInterprocedural -> + update valuation state >>-: fun state -> + Extlib.opt_fold start_recursive_call recursion state | IntraproceduralAll | IntraproceduralNonReferenced -> `Value G.empty in diff --git a/src/plugins/value/domains/inout_domain.ml b/src/plugins/value/domains/inout_domain.ml index a51098e16eb63723b7d82f5449f5e835ad5cf58f..bda7c81868aa9913ca0e5b03ba9d9f802203c482 100644 --- a/src/plugins/value/domains/inout_domain.ml +++ b/src/plugins/value/domains/inout_domain.ml @@ -241,9 +241,10 @@ module Internal let effects = Transfer.effects_assume to_z e in `Value (Transfer.catenate state effects) - let start_call _stmt _call _valuation _state = `Value LatticeInout.empty + let start_call _stmt _call _recursion _valuation _state = + `Value LatticeInout.empty - let finalize_call _stmt _call ~pre ~post = + let finalize_call _stmt _call _recursion ~pre ~post = `Value (Transfer.catenate pre post) let update _valuation state = `Value state diff --git a/src/plugins/value/domains/octagons.ml b/src/plugins/value/domains/octagons.ml index 2be0ff0dfa9e97bd2e36809c8ff2c47a932fa51b..e45b1c875de6bb8e1421c9064e1366382cf1982f 100644 --- a/src/plugins/value/domains/octagons.ml +++ b/src/plugins/value/domains/octagons.ml @@ -1216,17 +1216,29 @@ module Domain = struct let assume _stmt _exp _bool = update - let start_call _stmt call valuation state = + let start_recursive_call recursion state = + let vars = List.map fst recursion.substitution @ recursion.withdrawal in + List.fold_left State.remove state vars + + let start_call _stmt call recursion valuation state = if intraprocedural () then `Value (empty ()) else let state = { state with modified = Locations.Zone.bottom } in - let assign_formal state { formal; concrete; avalue } = - state >>- assign_variable formal concrete avalue valuation - in - List.fold_left assign_formal (`Value state) call.arguments + match recursion with + | Some recursion -> + (* No relation inferred from the assignment of formal parameters + for recursive calls, because the valuation cannot be used safely + as the substitution of local and formals variables has not been + applied to it. *) + `Value (start_recursive_call recursion state) + | None -> + let assign_formal state { formal; concrete; avalue } = + state >>- assign_variable formal concrete avalue valuation + in + List.fold_left assign_formal (`Value state) call.arguments - let finalize_call _stmt _call ~pre ~post = + let finalize_call _stmt _call _recursion ~pre ~post = if intraprocedural () then `Value (kill post.modified pre) else diff --git a/src/plugins/value/domains/offsm_domain.ml b/src/plugins/value/domains/offsm_domain.ml index a2d8355c3e27b361b452e9898deb331a9b9d2d0c..70f2f43cccafd606c62e5c4484da7feb9601dc4d 100644 --- a/src/plugins/value/domains/offsm_domain.ml +++ b/src/plugins/value/domains/offsm_domain.ml @@ -157,9 +157,15 @@ module Internal : Domain_builder.InputDomain let assume _ _ _ _ state = `Value state - let finalize_call _stmt _call ~pre:_ ~post = `Value post + let finalize_call _stmt _call _recursion ~pre:_ ~post = `Value post - let start_call _stmt _call valuation state = update valuation state + let start_recursive_call recursion state = + let vars = List.map fst recursion.substitution @ recursion.withdrawal in + Memory.remove_variables vars state + + let start_call _stmt _call recursion valuation state = + update valuation state >>-: fun state -> + Extlib.opt_fold start_recursive_call recursion state let show_expr _valuation _state _fmt _expr = () diff --git a/src/plugins/value/domains/simple_memory.ml b/src/plugins/value/domains/simple_memory.ml index 94a2f4c5f6ce72aa1a962f391fe0a76ef151b060..339d8edb25a19e8e4eb85906a1fe8c10e9f2ae5b 100644 --- a/src/plugins/value/domains/simple_memory.ml +++ b/src/plugins/value/domains/simple_memory.ml @@ -52,11 +52,17 @@ module Make_Memory (Value: Value) = struct module Initial_Values = struct let v = [] end module Deps = struct let l = [Ast.self] end - include Hptmap.Make (Base) (Value)(Hptmap.Comp_unused) (Initial_Values) (Deps) + include Hptmap.Make + (Base.Base) (Value) (Hptmap.Comp_unused) (Initial_Values) (Deps) let cache_name s = Hptmap_sig.PersistentCache ("Value." ^ Value.name ^ "." ^ s) + let disjoint_union = + let cache = cache_name "union" in + let decide _key _v1 _v2 = assert false in + join ~cache ~symmetric:true ~idempotent:true ~decide + let narrow = let module E = struct exception Bottom end in let cache = cache_name "narrow" in @@ -259,7 +265,14 @@ module Make_Internal (Info: sig val name: string end) (Value: Value) = struct abstraction of the domain itself. *) let assume _stmt _expr _pos = update - let start_call _stmt call _valuation state = + let start_recusive_call recursion state = + let state = remove_variables recursion.withdrawal state in + (* No collision should occur in the substitution. *) + let decide _key _v1 _v2 = assert false in + snd (replace_key ~decide recursion.base_substitution state) + + let start_call _stmt call recursion _valuation state = + let state = Extlib.opt_fold start_recusive_call recursion state in let bind_argument state argument = let typ = argument.formal.vtype in let loc = Main_locations.PLoc.eval_varinfo argument.formal in @@ -269,8 +282,17 @@ module Make_Internal (Info: sig val name: string end) (Value: Value) = struct let state = List.fold_left bind_argument state call.arguments in `Value state - let finalize_call _stmt call ~pre:_ ~post = + let finalize_recursive_call ~pre recursion state = + let shape = Base.Hptset.shape recursion.base_withdrawal in + let inter = inter_with_shape shape pre in + let state = disjoint_union state inter in + (* No collision should occur in the substitution. *) + let decide _key _v1 _v2 = assert false in + snd (replace_key ~decide recursion.base_substitution state) + + let finalize_call _stmt call recursion ~pre ~post = let kf_name = Kernel_function.get_name call.kf in + let post = Extlib.opt_fold (finalize_recursive_call ~pre) recursion post in match find_builtin kf_name, call.return with | None, _ | _, None -> `Value post | Some f, Some return -> diff --git a/src/plugins/value/domains/simpler_domains.mli b/src/plugins/value/domains/simpler_domains.mli index 37a1209a79b929a90d05f63ff1c3afd2adf57773..ba32d0d3d2e0fd94a2c579e668e52ec73563e775 100644 --- a/src/plugins/value/domains/simpler_domains.mli +++ b/src/plugins/value/domains/simpler_domains.mli @@ -42,7 +42,6 @@ type simple_call = { rest: exp list; (* Extra arguments. *) return: varinfo option; (* Fake varinfo where the result of the call is stored. *) - recursive: bool; (* Is the call recursive? *) } (** Simplest interface for an abstract domain. No exchange of information with diff --git a/src/plugins/value/domains/symbolic_locs.ml b/src/plugins/value/domains/symbolic_locs.ml index 2c2f51d88a24600c8c1640d4496547dc9926f048..bd2fab8b55a914f5c6639aef3a8a5c494a2fc54d 100644 --- a/src/plugins/value/domains/symbolic_locs.ml +++ b/src/plugins/value/domains/symbolic_locs.ml @@ -563,9 +563,15 @@ module Internal : Domain_builder.InputDomain let assume _stmt _exp _pos valuation state = update valuation state - let start_call _stmt _call valuation state = update valuation state + let start_recursive_call recursion state = + let vars = List.map fst recursion.substitution @ recursion.withdrawal in + Memory.remove_variables vars state + + let start_call _stmt _call recursion valuation state = + update valuation state >>-: fun state -> + Extlib.opt_fold start_recursive_call recursion state - let finalize_call _stmt _call ~pre:_ ~post = `Value post + let finalize_call _stmt _call _recursion ~pre:_ ~post = `Value post let show_expr _valuation _state _fmt _expr = () diff --git a/src/plugins/value/domains/traces_domain.ml b/src/plugins/value/domains/traces_domain.ml index 408114d15682d5121126bb154111f216bf67c8f6..5f566f15944666fa24003a90c4c87db494064deb 100644 --- a/src/plugins/value/domains/traces_domain.ml +++ b/src/plugins/value/domains/traces_domain.ml @@ -865,7 +865,7 @@ module Internal = struct let trans = Assume (stmt, e, pos) in `Value (Traces.add_trans state trans) - let start_call stmt call _valuation state = + let start_call stmt call _recursion _valuation state = let kf = call.Eval.kf in if Kernel_function.is_definition kf then let msg = Format.asprintf "start_call: %s (%b)" (Kernel_function.get_name call.Eval.kf) @@ -890,7 +890,7 @@ module Internal = struct (CallDeclared (call.Eval.kf, exps, Option.map Cil.var var)) in `Value {state with call_declared_function = true} - let finalize_call _stmt call ~pre:_ ~post = + let finalize_call _stmt call _recursion ~pre:_ ~post = if post.call_declared_function then `Value {post with call_declared_function = false} else diff --git a/src/plugins/value/domains/unit_domain.ml b/src/plugins/value/domains/unit_domain.ml index 5633d599dd564bf5884cb63af702ffe887c5eac9..0c90f11a4886e2b4ee61e7489581694a1039e50d 100644 --- a/src/plugins/value/domains/unit_domain.ml +++ b/src/plugins/value/domains/unit_domain.ml @@ -63,8 +63,8 @@ module Make let update _ _ = `Value () let assign _ _ _ _ _ _ = `Value () let assume _ _ _ _ _ = `Value () - let start_call _ _ _ _ = `Value () - let finalize_call _ _ ~pre:_ ~post:_ = `Value () + let start_call _ _ _ _ _ = `Value () + let finalize_call _ _ _ ~pre:_ ~post:_ = `Value () let show_expr _ _ _ _ = () let logic_assign _ _ _ = () diff --git a/src/plugins/value/engine/compute_functions.ml b/src/plugins/value/engine/compute_functions.ml index b622130d6e7c272654cfa450ebc47e2f5d7232d1..ece699c60df2f50dfa57448e281799a191c9e1f8 100644 --- a/src/plugins/value/engine/compute_functions.ml +++ b/src/plugins/value/engine/compute_functions.ml @@ -160,7 +160,7 @@ module Make (Abstract: Abstractions.Eva) = struct is the instruction at which the call takes place, and is used to update the statuses of the preconditions of [kf]. If [show_progress] is true, the callstack and additional information are printed. *) - let compute_using_spec_or_body call_kinstr call state = + let compute_using_spec_or_body call_kinstr call recursion state = let kf = call.kf in Value_results.mark_kf_as_called kf; let global = match call_kinstr with Kglobal -> true | _ -> false in @@ -172,9 +172,10 @@ module Make (Abstract: Abstractions.Eva) = struct Value_types.Callstack.pretty_short call_stack Cil_datatype.Location.pretty (Cil_datatype.Kinstr.loc call_kinstr); let use_spec = - if call.recursive then - `Spec (Recursion.empty_spec_for_recursive_call kf) - else + match recursion with + | Some { depth } when depth >= Value_parameters.RecursiveUnroll.get () -> + `Spec (Recursion.get_spec call_kinstr kf) + | _ -> match kf.fundec with | Declaration (_,_,_,_) -> `Spec (Annotations.funspec kf) | Definition (def, _) -> @@ -210,8 +211,10 @@ module Make (Abstract: Abstractions.Eva) = struct module MemExec = Mem_exec.Make (Abstract.Val) (Abstract.Dom) - let compute_and_cache_call stmt call init_state = - let default () = compute_using_spec_or_body (Kstmt stmt) call init_state in + let compute_and_cache_call stmt call recursion init_state = + let default () = + compute_using_spec_or_body (Kstmt stmt) call recursion init_state + in if Value_parameters.MemExecAll.get () then let args = List.map (fun {avalue} -> Eval.value_assigned avalue) call.arguments @@ -272,9 +275,9 @@ module Make (Abstract: Abstractions.Eva) = struct | [state] -> `Value state | s :: l -> `Value (List.fold_left Abstract.Dom.join s l) - let compute_call_or_builtin stmt call state = + let compute_call_or_builtin stmt call recursion state = match Builtins.find_builtin_override call.kf with - | None -> compute_and_cache_call stmt call state + | None -> compute_and_cache_call stmt call recursion state | Some (name, builtin, cacheable, spec) -> Value_results.mark_kf_as_called call.kf; let kinstr = Kstmt stmt in @@ -329,9 +332,11 @@ module Make (Abstract: Abstractions.Eva) = struct Value_util.push_call_stack kf Kglobal; store_initial_state kf init_state; let call = - {kf; arguments = []; rest = []; return = None; recursive = false} + { kf; callstack = []; arguments = []; rest = []; return = None; } + in + let final_result = + compute_using_spec_or_body Kglobal call None init_state in - let final_result = compute_using_spec_or_body Kglobal call init_state in let final_states = final_result.Transfer.states in let final_state = PowersetDomain.(final_states >>-: of_list >>- join) in Value_util.pop_call_stack (); diff --git a/src/plugins/value/engine/recursion.ml b/src/plugins/value/engine/recursion.ml index 99d150435c7d019f1cb0bd1a88f5ecb76e347f02..a5abcb4b90ed4470cda6e8ad546d2b8e071ef496 100644 --- a/src/plugins/value/engine/recursion.ml +++ b/src/plugins/value/engine/recursion.ml @@ -21,50 +21,51 @@ (**************************************************************************) open Cil_types +open Eval -(** Recursion *) - -(* Our current treatment for recursion -- use the specification for - the function that begins the recursive cycle -- is incorrect for - function with formals whose address is taken. Indeed, we do not know - which "instance" of the formal is updated by the specification. In - this case, warn the user. *) -let check_formals_non_referenced kf = - let formals = Kernel_function.get_formals kf in - if List.exists (fun vi -> vi.vaddrof) formals then - Value_parameters.error ~current:true ~once:true - "function '%a' (involved in a recursive call) has a formal parameter \ - whose address is taken. Analysis may be unsound." - Kernel_function.pretty kf +module Varinfo = Cil_datatype.Varinfo -let warn_recursive_call kf call_stack = - if Value_parameters.IgnoreRecursiveCalls.get () - then begin - Value_util.warning_once_current - "@[recursive call@ during@ value@ analysis@ of %a \ - @[(%a <- %a)@].@ Assuming@ the call@ has@ no effect.@ \ - The analysis@ will@ be@ unsound.@]" - Kernel_function.pretty kf Kernel_function.pretty kf - Value_types.Callstack.pretty call_stack ; - check_formals_non_referenced kf; - Db.Value.recursive_call_occurred kf; - end - else begin - Value_parameters.error ~once:true ~current:true - "@[@[detected@ recursive@ call@ (%a <- %a)@]@;@[Use %s@ to@ \ - ignore@ (beware@ this@ will@ make@ the analysis@ unsound)@]@]" - Kernel_function.pretty kf Value_types.Callstack.pretty call_stack - Value_parameters.IgnoreRecursiveCalls.option_name; - raise Db.Value.Aborted - end - -(* Check whether the function at the top of the call-stack starts a - recursive call. *) -let is_recursive_call kf = - let call_stack = Value_util.call_stack () in - if List.exists (fun (f, _) -> f == kf) call_stack - then (warn_recursive_call kf call_stack; true) - else false +let mark_unknown_requires kinstr kf funspec = + let stmt = + match kinstr with + | Kglobal -> assert false + | Kstmt stmt -> stmt + in + let emitter = Value_util.emitter in + let status = Property_status.Dont_know in + let emit_behavior behavior = + let emit_predicate predicate = + let ip = Property.ip_of_requires kf Kglobal behavior predicate in + Statuses_by_call.setup_precondition_proxy kf ip; + let property = Statuses_by_call.precondition_at_call kf ip stmt in + Property_status.emit ~distinct:true emitter ~hyps:[] property status + in + List.iter emit_predicate behavior.b_requires + in + List.iter emit_behavior funspec.spec_behavior + +let get_spec kinstr kf = + let funspec = Annotations.funspec ~populate:false kf in + if Cil.is_empty_funspec funspec then + Value_parameters.abort ~current:true + "@[Recursive call to %a@ without a specification.@ Try to increase@ \ + the %s parameter@ or write a specification@ for function %a.@]" + Kernel_function.pretty kf + Value_parameters.RecursiveUnroll.name + Kernel_function.pretty kf + else + let depth = Value_parameters.RecursiveUnroll.get () in + let () = + Value_parameters.warning ~once:true ~current:true + "@[Using specification of function %a@ for recursive calls%s.@ \ + Analysis of function %a@ is thus incomplete@ and its soundness@ \ + relies on the written specification.@]" + Kernel_function.pretty kf + (if depth > 0 then Format.asprintf " of depth %i" depth else "") + Kernel_function.pretty kf + in + mark_unknown_requires kinstr kf funspec; + funspec (* Find a spec for a function [kf] that begins a recursive call. If [kf] has no existing specification, generate (an incorrect) one, and warn @@ -89,7 +90,7 @@ let _spec_for_recursive_call kf = ~silent_about_merging_behav:true spec initial_spec; spec -let empty_spec_for_recursive_call kf = +let _empty_spec_for_recursive_call kf = let typ_res = Kernel_function.get_return_type kf in let empty = Cil.empty_funspec () in let assigns = @@ -104,3 +105,79 @@ let empty_spec_for_recursive_call kf = let bhv = Cil.mk_behavior ~assigns ~name:Cil.default_behavior_name () in empty.spec_behavior <- [bhv]; empty + + +(* -------------------------------------------------------------------------- *) + +module CallDepth = + Datatype.Pair_with_collections (Kernel_function) (Datatype.Int) + (struct let module_name = "CallDepth" end) + +module VarCopies = + Datatype.List (Datatype.Pair (Varinfo) (Varinfo)) + +module VarStack = + State_builder.Hashtbl + (CallDepth.Hashtbl) + (VarCopies) + (struct + let name = "Eva.Recursion.VarStack" + let dependencies = [ Ast.self ] + let size = 9 + end) + +let copy_variable fundec depth varinfo = + let name = Format.asprintf "\\copy<%s>[%i]" varinfo.vname depth in + let v = Cil.copyVarinfo varinfo name in + Cil.refresh_local_name fundec v; + v + +let make_stack (kf, depth) = + let fundec = + try Kernel_function.get_definition kf + with Kernel_function.No_Definition -> assert false + in + let vars = Kernel_function.(get_formals kf @ get_locals kf) in + let copy v = v, copy_variable fundec depth v in + List.map copy vars + +let get_stack kf depth = VarStack.memo make_stack (kf, depth) + +let make_recursion call depth = + let dkey = Value_parameters.dkey_recursion in + Value_parameters.feedback ~dkey ~once:true ~current:true + "@[detected recursive call@ of function %a.@]" + Kernel_function.pretty call.kf; + let substitution = get_stack call.kf depth in + let add_if_copy acc argument = + match argument.avalue with + | Copy ({ lval = Var vi, _ }, _) -> Varinfo.Set.add vi acc + | _ -> acc + in + let empty = Varinfo.Set.empty in + let copied_varinfos = List.fold_left add_if_copy empty call.arguments in + let may_be_used (vi, _) = vi.vaddrof || Varinfo.Set.mem vi copied_varinfos in + let substitution, withdrawal = List.partition may_be_used substitution in + let withdrawal = List.map fst withdrawal in + let base_of_varinfo (v1, v2) = Base.of_varinfo v1, Base.of_varinfo v2 in + let list_substitution = List.map base_of_varinfo substitution in + let base_substitution = Base.substitution_from_list list_substitution in + let list_withdrawal = List.map Base.of_varinfo withdrawal in + let base_withdrawal = Base.Hptset.of_list list_withdrawal in + { depth; substitution; base_substitution; withdrawal; base_withdrawal; } + +let make call = + let is_same_kf (f, _) = Kernel_function.equal f call.kf in + let previous_calls = List.filter is_same_kf call.callstack in + let depth = List.length previous_calls in + if depth > 0 + then Some (make_recursion call depth) + else None + +let revert recursion = + let revert (v1, v2) = v2, v1 in + let substitution = List.map revert recursion.substitution in + let base_of_varinfo (v1, v2) = Base.of_varinfo v1, Base.of_varinfo v2 in + let list = List.map base_of_varinfo substitution in + let base_substitution = Base.substitution_from_list list in + { recursion with substitution; base_substitution; } diff --git a/src/plugins/value/engine/recursion.mli b/src/plugins/value/engine/recursion.mli index 3a3255c47d1b22827ef20c36d711d349c5cd1492..d4f21920b0e191596613912e99c2c79f0811af2d 100644 --- a/src/plugins/value/engine/recursion.mli +++ b/src/plugins/value/engine/recursion.mli @@ -23,12 +23,16 @@ (** Handling of recursion cycles in the callgraph *) open Cil_types +open Eval -val is_recursive_call: kernel_function -> bool -(** Given the current state of the call stack, detect whether the - given given function would start a recursive cycle. *) +(* Returns the specification for a recursive call to the given function. Fails + if the function has no specification. Marks the preconditions of the call + as unknowns. *) +val get_spec: kinstr -> kernel_function -> funspec -val empty_spec_for_recursive_call: kernel_function -> spec -(** Generate an empty spec [assigns \nothing] or - [assigns \result \from \nothing], to be used to "approximate" the - results of a recursive call. *) +(** Creates the information about a recursive call. *) +val make: ('v, 'loc) call -> recursion option + +(** Changes the information about a recursive call to be used at the end + of the call. *) +val revert: recursion -> recursion diff --git a/src/plugins/value/engine/transfer_stmt.ml b/src/plugins/value/engine/transfer_stmt.ml index 040629aa88699be86afd064e0775d464398b4e34..7ba3de0d199c4f9439b87c9657f175d8ff83fc09 100644 --- a/src/plugins/value/engine/transfer_stmt.ml +++ b/src/plugins/value/engine/transfer_stmt.ml @@ -27,7 +27,7 @@ open Eval module type S = sig type state type value - type location + type loc val assign: state -> kinstr -> lval -> exp -> state or_bottom val assume: state -> stmt -> exp -> bool -> state or_bottom val call: @@ -44,7 +44,7 @@ module type S = sig builtin: bool; } val compute_call_ref: - (stmt -> (location, value) call -> state -> call_result) ref + (stmt -> (loc, value) call -> recursion option ->state -> call_result) ref end (* Reference filled in by the callwise-inout callback *) @@ -105,6 +105,17 @@ module DumpFileCounters = let name = "Transfer_stmt.DumpFileCounters" end) +module VarHashtbl = Cil_datatype.Varinfo.Hashtbl + +let substitution_visitor table = object + inherit Visitor.frama_c_copy (Project.current ()) + + method! vvrbl varinfo = + match VarHashtbl.find_opt table varinfo with + | None -> Cil.JustCopy + | Some vi -> Cil.ChangeTo vi +end + module Make (Abstract: Abstractions.Eva) = struct module Value = Abstract.Val @@ -114,7 +125,7 @@ module Make (Abstract: Abstractions.Eva) = struct type state = Domain.t type value = Value.t - type location = Location.location + type loc = Location.location (* When using a product of domains, a product of states may have no concretization (if the domains have inferred incompatible properties) @@ -295,13 +306,13 @@ module Make (Abstract: Abstractions.Eva) = struct } (* Forward reference to [Eval_funs.compute_call] *) - let compute_call_ref - : (stmt -> (location, value) call -> Domain.state -> call_result) ref + let compute_call_ref : + (stmt -> (loc, value) call -> recursion option -> state -> call_result) ref = ref (fun _ -> assert false) (* Returns the result of a call, and a boolean that indicates whether a builtin has been used to interpret the call. *) - let process_call stmt call valuation state = + let process_call stmt call recursion valuation state = Value_util.push_call_stack call.kf (Kstmt stmt); let cleanup () = Value_util.pop_call_stack (); @@ -312,10 +323,10 @@ module Make (Abstract: Abstractions.Eva) = struct let domain_valuation = Eval.to_domain_valuation valuation in let res = (* Process the call according to the domain decision. *) - match Domain.start_call stmt call domain_valuation state with + match Domain.start_call stmt call recursion domain_valuation state with | `Value state -> Domain.Store.register_initial_state (Value_util.call_stack ()) state; - !compute_call_ref stmt call state + !compute_call_ref stmt call recursion state | `Bottom -> { states = `Bottom; cacheable = Cacheable; builtin=false } in @@ -449,11 +460,11 @@ module Make (Abstract: Abstractions.Eva) = struct Kernel_function.get_formals kf @ locals (* Do the call to one function. *) - let do_one_call valuation stmt lv call state = + let do_one_call valuation stmt lv call recursion state = let kf_callee = call.kf in let pre = state in (* Process the call according to the domain decision. *) - let call_result = process_call stmt call valuation state in + let call_result = process_call stmt call recursion valuation state in call_result.cacheable, call_result.states >>- fun result -> let leaving_vars = leaving_vars kf_callee in @@ -472,22 +483,15 @@ module Make (Abstract: Abstractions.Eva) = struct >>- fun reductions -> (* The formals (and the locals) of the called function leave scope. *) let post = Domain.leave_scope kf_callee leaving_vars state in + let recursion = Option.map Recursion.revert recursion in (* Computes the state after the call, from the post state at the end of the called function, and the pre state at the call site. *) - Domain.finalize_call stmt call ~pre ~post >>- fun state -> + Domain.finalize_call stmt call recursion ~pre ~post >>- fun state -> (* Backward propagates the [reductions] on the concrete arguments. *) reduce_arguments reductions state >>- fun state -> treat_return ~kf_callee lv call.return stmt state - and process_recursive state = - (* When the call is recursive, formals have not been added to the - domains. Do not reduce them, and more importantly, do not remove - them from the scope. (Because the instance from the initial, - non-recursive, call are still present.) *) - Domain.finalize_call stmt call ~pre ~post:state >>- fun state -> - treat_return ~kf_callee lv call.return stmt state in let states = - let process = if call.recursive then process_recursive else process in List.fold_left (fun acc return -> Bottom.add_to_list (process return) acc) [] result @@ -533,30 +537,45 @@ module Make (Abstract: Abstractions.Eva) = struct (* Create an Eval.call *) let create_call kf args = - let recursive = Recursion.is_recursive_call kf in let return = Library_functions.get_retres_vi kf in + let callstack = Value_util.call_stack () in let arguments, rest = - if recursive then - (* For recursive calls, we evaluate 'assigns \result \from \nothing' - using a specification. We generate a dummy [call] object in which - formals are not present. This way, domains will not overwrite - the formals of the recursive function (which would be present - in scope twice). *) - [], [] - else - let formals = Kernel_function.get_formals kf in - let rec format_arguments acc args formals = match args, formals with - | _, [] -> acc, args - | [], _ -> assert false - | (concrete, avalue) :: args, formal :: formals -> - let argument = { formal ; concrete; avalue } in - format_arguments (argument :: acc) args formals - in - let arguments, rest = format_arguments [] args formals in - let arguments = List.rev arguments in - arguments, rest + let formals = Kernel_function.get_formals kf in + let rec format_arguments acc args formals = match args, formals with + | _, [] -> acc, args + | [], _ -> assert false + | (concrete, avalue) :: args, formal :: formals -> + let argument = { formal ; concrete; avalue } in + format_arguments (argument :: acc) args formals + in + let arguments, rest = format_arguments [] args formals in + let arguments = List.rev arguments in + arguments, rest + in + {kf; callstack; arguments; rest; return; } + + let replace_value visitor substitution = function + | Assign value -> Assign (Value.replace_base substitution value) + | Copy (loc, flagged) -> + let v = flagged.v >>-: Value.replace_base substitution in + let flagged = { flagged with v } in + let lloc = Location.replace_base substitution loc.lloc in + let lval = Visitor.visitFramacLval visitor loc.lval in + let loc = { loc with lval; lloc } in + Copy (loc, flagged) + + let replace_recursive_call recursion call = + let tbl = VarHashtbl.create 9 in + List.iter (fun (v1, v2) -> VarHashtbl.add tbl v1 v2) recursion.substitution; + let visitor = substitution_visitor tbl in + let base_substitution = recursion.base_substitution in + let replace_arg argument = + let concrete = Visitor.visitFramacExpr visitor argument.concrete in + let avalue = replace_value visitor base_substitution argument.avalue in + { argument with concrete; avalue } in - {kf; arguments; rest; return; recursive} + let arguments = List.map replace_arg call.arguments in + { call with arguments; } let make_call ~subdivnb kf arguments valuation state = (* Evaluate the arguments of the call. *) @@ -564,8 +583,9 @@ module Make (Abstract: Abstractions.Eva) = struct compute_actuals ~subdivnb ~determinate valuation state arguments >>=: fun (args, valuation) -> let call = create_call kf args in - call, valuation - + let recursion = Recursion.make call in + let call = Extlib.opt_fold replace_recursive_call recursion call in + call, recursion, valuation (* ----------------- show_each and dump_each directives ------------------- *) @@ -744,11 +764,13 @@ module Make (Abstract: Abstractions.Eva) = struct (* Create the call. *) let eval, alarms = make_call ~subdivnb kf args valuation state in Alarmset.emit ki_call alarms; - eval >>- fun (call, valuation) -> + eval >>- fun (call, recursion, valuation) -> (* Register the call. *) Value_results.add_kf_caller call.kf ~caller:(current_kf, stmt); (* Do the call. *) - let c, states = do_one_call valuation stmt lval_option call state in + let c, states = + do_one_call valuation stmt lval_option call recursion state + in (* If needed, propagate that callers cannot be cached. *) if c = NoCacheCallers then cacheable := NoCacheCallers; diff --git a/src/plugins/value/engine/transfer_stmt.mli b/src/plugins/value/engine/transfer_stmt.mli index af7e5fa3e7383125abfbb9101e64a23d5b8f9baf..87c505e24111ca06f51ce4a9cb5ee3fe9178c788 100644 --- a/src/plugins/value/engine/transfer_stmt.mli +++ b/src/plugins/value/engine/transfer_stmt.mli @@ -29,7 +29,7 @@ module type S = sig type state type value - type location + type loc val assign: state -> kinstr -> lval -> exp -> state or_bottom @@ -55,13 +55,13 @@ module type S = sig } val compute_call_ref: - (stmt -> (location, value) call -> state -> call_result) ref + (stmt -> (loc, value) call -> recursion option -> state -> call_result) ref end module Make (Abstract: Abstractions.Eva) : S with type state = Abstract.Dom.t and type value = Abstract.Val.t - and type location = Abstract.Loc.location + and type loc = Abstract.Loc.location (* Local Variables: diff --git a/src/plugins/value/eval.ml b/src/plugins/value/eval.ml index 8aab315162a3557beba3835d1b3c821ded536474..7a12a168d662e1d7225531415b317ba18e5bfbaf 100644 --- a/src/plugins/value/eval.ml +++ b/src/plugins/value/eval.ml @@ -240,12 +240,24 @@ type ('loc, 'value) argument = { avalue: ('loc, 'value) assigned; } + +type call_site = kernel_function * kinstr +type callstack = call_site list + type ('loc, 'value) call = { kf: kernel_function; + callstack: callstack; arguments: ('loc, 'value) argument list; rest: (exp * ('loc, 'value) assigned) list; return: varinfo option; - recursive: bool; +} + +type recursion = { + depth: int; + substitution: (varinfo * varinfo) list; + base_substitution: Base.substitution; + withdrawal: varinfo list; + base_withdrawal: Base.Hptset.t; } type cacheable = Cacheable | NoCache | NoCacheCallers diff --git a/src/plugins/value/eval.mli b/src/plugins/value/eval.mli index e050aae784876740fd329e70493c9876495131ef..5714172358fc24dfbc4ba07a05c4fe2722fcb2b0 100644 --- a/src/plugins/value/eval.mli +++ b/src/plugins/value/eval.mli @@ -215,7 +215,6 @@ type 'location logic_assign = (** {2 Interprocedural Analysis } *) (* -------------------------------------------------------------------------- *) - (** Argument of a function call. *) type ('loc, 'value) argument = { formal: varinfo; (** The formal argument of the called function. *) @@ -223,19 +222,55 @@ type ('loc, 'value) argument = { avalue: ('loc, 'value) assigned; (** The value of the concrete argument. *) } +(** A call_stack is a list, telling which function was called at which + site. The head of the list tells about the latest call. *) + +(** A call site: the function called, and the call statement + (or [Kglobal] for the main function. *) +type call_site = kernel_function * kinstr + +(* A call stack is a list of call sites. The head is the latest call. + The last element is the main function. *) +type callstack = call_site list + (** A function call. *) type ('loc, 'value) call = { kf: kernel_function; (** The called function. *) + callstack: callstack; (** The current callstack + (without this call). *) arguments: ('loc, 'value) argument list; (** The arguments of the call. *) rest: (exp * ('loc, 'value) assigned) list; (** Extra-arguments. *) return: varinfo option; (** Fake varinfo to store the return value of the call. Same varinfo for every call to a given function. *) - recursive: bool; } -(* Can the results of a function call be cached with memexec? *) +(** Information needed to interpret a recursive call. + The local variables and formal parameters of different recursive calls + should not be mixed up. Those of the current call must be temporary withdraw + or replaced from the domain states before starting the new recursive call, + and the inverse transformation must be made at the end of the call. *) +type recursion = { + depth: int; + (** Depth of the recursive call, i.e. the number of previous call to the + called function in the current callstack. *) + substitution: (varinfo * varinfo) list; + (** List of variables substitutions to be performed by the domains: for each + pair, the first variable must be replaced by the second one in the domain + state. *) + base_substitution: Base.substitution; + (** Same substitution as the previous field, for bases. *) + withdrawal: varinfo list; + (** List of variables to be temporary removed from the state at the start of a + new recursive call (by the function [start_call] of the abstract domains), + or to be put back in the state at the end of a recursive call (by the + function [finalize_call] of the abstract domains). *) + base_withdrawal: Base.Hptset.t; + (** Same withdrawal as the previous field, for bases. *) +} + +(** Can the results of a function call be cached with memexec? *) type cacheable = | Cacheable (** Functions whose result can be safely cached *) | NoCache (** Functions whose result should not be cached, but for diff --git a/src/plugins/value/utils/value_util.ml b/src/plugins/value/utils/value_util.ml index 00f2871518eca24188ce2f575e0bfdc71771c7c6..13a005dd2afb149c347bfdd8ed45f51fd90b3262 100644 --- a/src/plugins/value/utils/value_util.ml +++ b/src/plugins/value/utils/value_util.ml @@ -24,11 +24,7 @@ open Cil_types (* Callstacks related types and functions *) -(* Function called, and calling instruction. *) -type call_site = (kernel_function * kinstr) -type callstack = call_site list - -let call_stack : callstack ref = ref [] +let call_stack : Value_types.callstack ref = ref [] (* let call_stack_for_callbacks : (kernel_function * kinstr) list ref = ref [] *) let clear_call_stack () = diff --git a/src/plugins/value/utils/value_util.mli b/src/plugins/value/utils/value_util.mli index 61df6ce5331ea7d09ef8efb35e2e607bb5f3d0e5..0bfe89cbe916816878319417b0dc123ad79bea1c 100644 --- a/src/plugins/value/utils/value_util.mli +++ b/src/plugins/value/utils/value_util.mli @@ -24,11 +24,6 @@ open Cil_types (** {2 Callstacks related types and functions} *) -(** A call_stack is a list, telling which function was called at which - site. The head of the list tells about the latest call. *) -type call_site = (kernel_function * kinstr) -type callstack = call_site list - (** Functions dealing with call stacks. *) val clear_call_stack : unit -> unit val pop_call_stack : unit -> unit @@ -36,7 +31,7 @@ val push_call_stack : kernel_function -> kinstr -> unit (** The current function is the one on top of the call stack. *) val current_kf : unit -> kernel_function -val call_stack : unit -> callstack +val call_stack : unit -> Value_types.callstack (** Prints the current callstack. *) val pp_callstack : Format.formatter -> unit diff --git a/src/plugins/value/value_parameters.ml b/src/plugins/value/value_parameters.ml index c6027b04ee524ef02df19d3980becc6a53f9a74b..a3d0cb97c5034a4eff502b76729e1d3245bf20a6 100644 --- a/src/plugins/value/value_parameters.ml +++ b/src/plugins/value/value_parameters.ml @@ -82,11 +82,13 @@ let dkey_incompatible_states = register_category "incompatible-states" let dkey_iterator = register_category "iterator" let dkey_callbacks = register_category "callbacks" let dkey_widening = register_category "widening" +let dkey_recursion = register_category "recursion" let () = let activate dkey = add_debug_keys dkey in List.iter activate - [dkey_initial_state; dkey_final_states; dkey_summary; dkey_cvalue_domain] + [dkey_initial_state; dkey_final_states; dkey_summary; dkey_cvalue_domain; + dkey_recursion; ] (* Warning categories. *) let wkey_alarm = register_warn_category "alarm" @@ -509,15 +511,20 @@ module WarnPointerSubstraction = let () = add_correctness_dep WarnPointerSubstraction.parameter let () = Parameter_customize.set_group alarms +let () = Parameter_customize.is_invisible () module IgnoreRecursiveCalls = False (struct let option_name = "-eva-ignore-recursive-calls" - let help = - "Pretend function calls that would be recursive do not happen. \ - Causes unsoundness" + let help = "Deprecated." end) -let () = add_correctness_dep IgnoreRecursiveCalls.parameter +let () = + IgnoreRecursiveCalls.add_set_hook + (fun _old _new -> + warning + "@[Option -eva-ignore-recursive-calls has no effect.@ Recursive calls \ + can be unrolled@ through option -eva-unroll-recursive-calls,@ or their \ + specification is used@ to interpret them.@]") let () = Parameter_customize.set_group alarms @@ -671,6 +678,19 @@ module WideningPeriod = let () = WideningPeriod.set_range ~min:1 ~max:max_int let () = add_precision_dep WideningPeriod.parameter +let () = Parameter_customize.set_group precision_tuning +module RecursiveUnroll = + Int + (struct + let default = 0 + let option_name = "-eva-unroll-recursive-calls" + let arg_name = "n" + let help = "Unroll <n> recursive calls before using the specification of \ + the recursive function to interpret the calls." + end) +let () = RecursiveUnroll.set_range ~min:0 ~max:max_int +let () = add_precision_dep RecursiveUnroll.parameter + (* --- Partitioning --- *) let () = Parameter_customize.set_group precision_tuning diff --git a/src/plugins/value/value_parameters.mli b/src/plugins/value/value_parameters.mli index 9a6a7172cc20cf89b2a178a6bf40c59cf1e91779..23ce27ed5dedf966bf1a5aeba9c6613aa60caea9 100644 --- a/src/plugins/value/value_parameters.mli +++ b/src/plugins/value/value_parameters.mli @@ -65,13 +65,13 @@ module WarnSignedConvertedDowncast: Parameter_sig.Bool module WarnPointerSubstraction: Parameter_sig.Bool module WarnCopyIndeterminate: Parameter_sig.Kernel_function_set -module IgnoreRecursiveCalls: Parameter_sig.Bool - module DescendingIteration: Parameter_sig.String module HierarchicalConvergence: Parameter_sig.Bool module WideningDelay: Parameter_sig.Int module WideningPeriod: Parameter_sig.Int +module RecursiveUnroll: Parameter_sig.Int + module SemanticUnrollingLevel: Parameter_sig.Int module SlevelFunction: Parameter_sig.Map with type key = Cil_types.kernel_function @@ -218,6 +218,9 @@ val dkey_callbacks : category (** Debug category used to print the usage of widenings. *) val dkey_widening : category +(** Debug category used to print messages about recursive calls. *) +val dkey_recursion : category + (** Registers available cvalue builtins for the -eva-builtin option. *) val register_builtin: string -> unit diff --git a/src/plugins/value/values/abstract_location.mli b/src/plugins/value/values/abstract_location.mli index df2247048bea90ea926809c6af7823d35c41f879..40419bfc573c0b96ea2682ac138d10deeea0386f 100644 --- a/src/plugins/value/values/abstract_location.mli +++ b/src/plugins/value/values/abstract_location.mli @@ -44,6 +44,10 @@ module type S = sig val to_value : location -> value val size : location -> Int_Base.t + (** [replace_base substitution location] replaces the variables represented + by the [location] according to [substitution]. *) + val replace_base: Base.substitution -> location -> location + (** {3 Alarms } *) (** These functions are used to create the alarms that report undesirable diff --git a/src/plugins/value/values/abstract_value.mli b/src/plugins/value/values/abstract_value.mli index 05e465434ffa50ad28ba262aeceb2c599fd111bc..50fb3525cae4491c7d1ad3800558923cc3c1066f 100644 --- a/src/plugins/value/values/abstract_value.mli +++ b/src/plugins/value/values/abstract_value.mli @@ -182,12 +182,18 @@ module type S = sig dst_val: t -> t option or_bottom + (** {3 Misc } *) + val resolve_functions : t -> Kernel_function.t list or_top * bool (** [resolve_functions v] returns the list of functions that may be pointed to by the abstract value [v] (representing a function pointer). The returned boolean must be [true] if some of the values represented by [v] do not correspond to functions. It is always safe to return [`Top, true]. *) + (** For pointer values, [replace_base substitution value] replaces the bases + pointed to by [value] according to [substitution]. For arithmetic values, + this function returns the [value] unchanged. *) + val replace_base: Base.substitution -> t -> t end type 'v key = 'v Structure.Key_Value.key diff --git a/src/plugins/value/values/main_locations.ml b/src/plugins/value/values/main_locations.ml index 7aab78471dfd377d2cd409d4313505a8bfee7363..7dd75133117b2ccb5902dc3afc4f1026b51ee176 100644 --- a/src/plugins/value/values/main_locations.ml +++ b/src/plugins/value/values/main_locations.ml @@ -62,6 +62,8 @@ module PLoc = struct else `Unknown (l1, l2) else `True + let replace_base = Precise_locs.replace_base + (* ------------------------------------------------------------------------ *) (* Offsets *) (* ------------------------------------------------------------------------ *) diff --git a/src/plugins/value/values/main_values.ml b/src/plugins/value/values/main_values.ml index b21f868739e43063cf196d40e5aa1ebea5b3b811..b38d4fcaf3a3eb938642682fc965784ee137b0f2 100644 --- a/src/plugins/value/values/main_values.ml +++ b/src/plugins/value/values/main_values.ml @@ -132,6 +132,8 @@ module CVal = struct let kfs, alarm = Locations.Location_Bytes.fold_topset_ok aux v init in `Value kfs, alarm with Abstract_interp.Error_Top -> `Top, true + + let replace_base substitution t = snd (Cvalue.V.replace_base substitution t) end module Interval = struct @@ -175,6 +177,7 @@ module Interval = struct let forward_cast ~src_type:_ ~dst_type:_ _ = `Value top let resolve_functions _ = `Top, true + let replace_base _substitution t = t let rewrap_integer range value = match value with diff --git a/src/plugins/value/values/numerors/numerors_value.ml b/src/plugins/value/values/numerors/numerors_value.ml index 2832d06cb3586316b5fe2fa311b2cb2f05e7a3ce..5381969a55fc736414ca52827754b99f6b22cd00 100644 --- a/src/plugins/value/values/numerors/numerors_value.ml +++ b/src/plugins/value/values/numerors/numerors_value.ml @@ -318,6 +318,7 @@ let assume_comparable _cmp v1 v2 = `Unknown (v1, v2) let rewrap_integer _ _ = top let backward_cast ~src_typ:_ ~dst_typ:_ ~src_val:_ ~dst_val:_ = `Value None let resolve_functions _ = `Top, true +let replace_base _substitution t = t (*----------------------------------------------------------------------------- diff --git a/src/plugins/value/values/offsm_value.ml b/src/plugins/value/values/offsm_value.ml index b46b11002e82269573247c93bebfb48e5e102bb7..f6fd8d3fd663c0c763a80f814b1d343015a6cabe 100644 --- a/src/plugins/value/values/offsm_value.ml +++ b/src/plugins/value/values/offsm_value.ml @@ -434,6 +434,11 @@ module Offsm : Abstract_value.Leaf with type t = offsm_or_top = struct else Top let resolve_functions _ = `Top, true (* TODO: extract value *) + let replace_base substitution = function + | Top -> Top + | O offsm -> + let f v = snd (Cvalue.V_Or_Uninitialized.replace_base substitution v) in + O (Cvalue.V_Offsetmap.map_on_values f offsm) let forward_unop _typ op o = let o' = match o, op with diff --git a/src/plugins/value/values/sign_value.ml b/src/plugins/value/values/sign_value.ml index b9f59f90e277c5ef875801640ea6f98d3987a801..08334941537bb65fd0931def46400ca033e12a12 100644 --- a/src/plugins/value/values/sign_value.ml +++ b/src/plugins/value/values/sign_value.ml @@ -107,6 +107,8 @@ let constant _ = function precisely *) let resolve_functions _ = `Top, true +let replace_base _substitution t = t + (** {2 Alarms} *) let assume_non_zero v = diff --git a/src/plugins/value/values/value_product.ml b/src/plugins/value/values/value_product.ml index 7e89f1fc751c739bdd1e262ae99ab1b6871f2136..03ec02d71f2b735936b3e84186198d8da1bf5cd9 100644 --- a/src/plugins/value/values/value_product.ml +++ b/src/plugins/value/values/value_product.ml @@ -125,6 +125,10 @@ module Make in list, b1 && b2 + let replace_base substitution (left, right) = + Left.replace_base substitution left, + Right.replace_base substitution right + let reduce (orig_left, orig_right) left right = match left, right with | None, None -> None | Some left, None -> Some (left, orig_right) diff --git a/src/plugins/value_types/cvalue.ml b/src/plugins/value_types/cvalue.ml index a545314edfe9d57bca80a5b37ab7d504a507f032..0fdd5f2fea59bd6a63b227433c8c022e8b681597 100644 --- a/src/plugins/value_types/cvalue.ml +++ b/src/plugins/value_types/cvalue.ml @@ -909,6 +909,10 @@ module V_Or_Uninitialized = struct in removed, t' + let replace_base substitution t = + let modified, v = V.replace_base substitution (get_v t) in + modified, if modified then create (get_flags t) v else t + let reduce_by_initializedness pos v = if pos then meet v (C_init_esc V.top) diff --git a/src/plugins/value_types/cvalue.mli b/src/plugins/value_types/cvalue.mli index a5c93243c0b2de1d3eeea18c3f4882e641652a3c..717c387372fd1c049d6809987a8ced77534c0271 100644 --- a/src/plugins/value_types/cvalue.mli +++ b/src/plugins/value_types/cvalue.mli @@ -226,6 +226,8 @@ module V_Or_Uninitialized : sig val unspecify_escaping_locals : exact:bool -> (V.M.key -> bool) -> t -> bool * t + val replace_base: Base.substitution -> t -> bool * t + val map: (V.t -> V.t) -> t -> t val map2: (V.t -> V.t -> V.t) -> t -> t -> t (** initialized/escaping information is the join of the information diff --git a/src/plugins/value_types/precise_locs.ml b/src/plugins/value_types/precise_locs.ml index 63faec349a5f9d1741de1363f98e5dee1ed6ab9d..905339d0fd2bde08242a5848f8285700b8fff543 100644 --- a/src/plugins/value_types/precise_locs.ml +++ b/src/plugins/value_types/precise_locs.ml @@ -263,6 +263,25 @@ let loc_top = { } let is_top_loc pl = equal_loc loc_top pl +let replace_base substitution po = + match po.loc with + | PLBottom -> po + | PLLoc loc -> + let modified, loc = Location_Bits.replace_base substitution loc in + if modified then { po with loc = PLLoc loc } else po + | PLVarOffset (base, offset) -> + let set = Base.Hptset.singleton base in + let modified, set = Base.Hptset.replace substitution set in + if modified then + let base = Option.get (Base.Hptset.contains_single_elt set) in + { po with loc = PLVarOffset (base, offset) } + else po + | PLLocOffset (loc, offset) -> + let modified, loc = Location_Bits.replace_base substitution loc in + if modified + then { po with loc = PLLocOffset (loc, offset) } + else po + let rec fold_offset f po acc = match po with | POBottom -> f Ival.bottom acc diff --git a/src/plugins/value_types/precise_locs.mli b/src/plugins/value_types/precise_locs.mli index ba93233b11aecd14f15cb2d1cc2f355e6ee8d90a..cdff5d94de1b25b9f069419c0ba6c2424177f861 100644 --- a/src/plugins/value_types/precise_locs.mli +++ b/src/plugins/value_types/precise_locs.mli @@ -84,6 +84,8 @@ val is_bottom_loc: precise_location -> bool val loc_top : precise_location val is_top_loc: precise_location -> bool +val replace_base: Base.substitution -> precise_location -> precise_location + val fold: (Locations.location -> 'a -> 'a) -> precise_location -> 'a -> 'a diff --git a/src/plugins/variadic/tests/defined/oracle/recursive.res.oracle b/src/plugins/variadic/tests/defined/oracle/recursive.res.oracle index 9fcbfae2ed2afb6f4498cd8fc01efebb747ea53f..6b943ccd65a9ce9d811f61abbd5135a75d1d49d0 100644 --- a/src/plugins/variadic/tests/defined/oracle/recursive.res.oracle +++ b/src/plugins/variadic/tests/defined/oracle/recursive.res.oracle @@ -6,15 +6,12 @@ [eva] Analyzing a complete application starting at main [eva] Computing initial state [eva] Initial state computed -[eva] tests/defined/recursive.i:8: Warning: - recursive call during value analysis - of f (f <- f :: tests/defined/recursive.i:12 <- main). Assuming the call has - no effect. The analysis will be unsound. -[eva] using specification for function f +[eva:recursion] tests/defined/recursive.i:8: + detected recursive call of function f. [eva] done for function main [eva] ====== VALUES COMPUTED ====== [eva:final-states] Values at end of function f: - __retres ∈ [--..--] + __retres ∈ {42} [eva:final-states] Values at end of function main: /* Generated by Frama-C */ diff --git a/src/plugins/variadic/tests/defined/recursive.i b/src/plugins/variadic/tests/defined/recursive.i index 0757bce330528a5298ebf08e1358a169dcce5d91..35ce1f080d5b5dd8eb702afe9abb829a903d77ec 100644 --- a/src/plugins/variadic/tests/defined/recursive.i +++ b/src/plugins/variadic/tests/defined/recursive.i @@ -1,5 +1,5 @@ /* run.config -STDOPT: +"-eva-ignore-recursive-calls" +STDOPT: +"-eva-unroll-recursive-calls 10" */ int f(int a, ...){ if(a <= 0) diff --git a/tests/misc/audit-in.json b/tests/misc/audit-in.json index 4278dcffc0935c685a650032aba687e7f8ba817a..580f8ac0b0bf71f754b3f4a4b99a41655e8886e6 100644 --- a/tests/misc/audit-in.json +++ b/tests/misc/audit-in.json @@ -35,7 +35,6 @@ "-eva-context-depth": "2", "-eva-context-valid-pointers": "false", "-eva-context-width": "2", - "-eva-ignore-recursive-calls": "false", "-eva-initialization-padding-globals": "yes", "-eva-initialized-locals": "false", "-eva-new-initial-state": "0", diff --git a/tests/misc/oracle/audit-out.json b/tests/misc/oracle/audit-out.json index c12464699ba37e8bab645ecf123b3ca67f8bd9bd..b7d55c35d2b08c652da0b87c0ac9f06e6d2abe66 100644 --- a/tests/misc/oracle/audit-out.json +++ b/tests/misc/oracle/audit-out.json @@ -9,7 +9,6 @@ "-eva-context-depth": "2", "-eva-context-valid-pointers": "false", "-eva-context-width": "2", - "-eva-ignore-recursive-calls": "false", "-eva-initialization-padding-globals": "yes", "-eva-initialized-locals": "false", "-eva-new-initial-state": "0", diff --git a/tests/value/oracle/rec.res.oracle b/tests/value/oracle/rec.res.oracle deleted file mode 100644 index 1db02fb5692032ddfd08d1f0c71ac1781acb47ad..0000000000000000000000000000000000000000 --- a/tests/value/oracle/rec.res.oracle +++ /dev/null @@ -1,22 +0,0 @@ -[kernel] Parsing tests/value/rec.i (no preprocessing) -[eva] Analyzing a complete application starting at main -[eva] Computing initial state -[eva] Initial state computed -[eva:initial-state] Values of globals at initialization - -[eva] Recording results for main -[eva] done for function main -[eva] ====== VALUES COMPUTED ====== -[eva:final-states] Values at end of function main: - X ∈ {0} -[from] Computing for function main -[from] Done for function main -[from] ====== DEPENDENCIES COMPUTED ====== - These dependencies hold at termination for the executions that terminate: -[from] Function main: - NO EFFECTS -[from] ====== END OF DEPENDENCIES ====== -[inout] Out (internal) for function main: - X -[inout] Inputs for function main: - \nothing diff --git a/tests/value/oracle/recursion.0.res.oracle b/tests/value/oracle/recursion.0.res.oracle index 11c074e5b372b9701116afdea0737dc70dd5e8d4..ce21d446188bb4c6d799e48dd493768b5edd735b 100644 --- a/tests/value/oracle/recursion.0.res.oracle +++ b/tests/value/oracle/recursion.0.res.oracle @@ -1,21 +1,632 @@ -[kernel] Parsing tests/value/recursion.i (no preprocessing) -[eva] Analyzing an incomplete application starting at main +[kernel] Parsing tests/value/recursion.c (with preprocessing) +[eva] Analyzing a complete application starting at main [eva] Computing initial state [eva] Initial state computed [eva:initial-state] Values of globals at initialization - G ∈ [--..--] + nondet ∈ [--..--] + p ∈ {0} +[eva:recursion] tests/value/recursion.c:18: + detected recursive call of function five. +[eva] tests/value/recursion.c:18: Warning: + Using specification of function five for recursive calls. + Analysis of function five is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function five +[eva:alarm] tests/value/recursion.c:15: Warning: + function five: postcondition got status unknown. +[eva] tests/value/recursion.c:342: Frama_C_show_each_5: {5} +[eva:recursion] tests/value/recursion.c:28: + detected recursive call of function sum. +[eva] tests/value/recursion.c:28: Warning: + Using specification of function sum for recursive calls. + Analysis of function sum is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function sum +[eva:alarm] tests/value/recursion.c:24: Warning: + function sum: postcondition got status unknown. +[eva] tests/value/recursion.c:344: Frama_C_show_each_91: {91} +[eva:recursion] tests/value/recursion.c:37: + detected recursive call of function factorial. +[eva] tests/value/recursion.c:37: Warning: + Using specification of function factorial for recursive calls. + Analysis of function factorial is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function factorial +[eva] tests/value/recursion.c:346: Frama_C_show_each_120: [0..4294967295] +[eva:recursion] tests/value/recursion.c:46: + detected recursive call of function syracuse. +[eva] tests/value/recursion.c:46: Warning: + Using specification of function syracuse for recursive calls. + Analysis of function syracuse is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function syracuse +[eva] tests/value/recursion.c:348: Frama_C_show_each_1: [0..4294967294] +[eva:recursion] tests/value/recursion.c:59: + detected recursive call of function fibonacci. +[eva] tests/value/recursion.c:59: Warning: + Using specification of function fibonacci for recursive calls. + Analysis of function fibonacci is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function fibonacci +[eva:recursion] tests/value/recursion.c:60: + detected recursive call of function fibonacci. +[eva] tests/value/recursion.c:60: Warning: + Using specification of function fibonacci for recursive calls. + Analysis of function fibonacci is thus incomplete and its soundness + relies on the written specification. +[eva] tests/value/recursion.c:350: Frama_C_show_each_89: [0..4294967295] +[eva:recursion] tests/value/recursion.c:76: + detected recursive call of function sum_ptr. +[eva] tests/value/recursion.c:76: Warning: + Using specification of function sum_ptr for recursive calls. + Analysis of function sum_ptr is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function sum_ptr +[eva:alarm] tests/value/recursion.c:68: Warning: + function sum_ptr: postcondition got status unknown. +[eva:alarm] tests/value/recursion.c:69: Warning: + function sum_ptr: postcondition got status unknown. +[eva] tests/value/recursion.c:355: Frama_C_show_each_91: {91} +[eva:recursion] tests/value/recursion.c:89: + detected recursive call of function factorial_ptr. +[eva] tests/value/recursion.c:89: Warning: + Using specification of function factorial_ptr for recursive calls. + Analysis of function factorial_ptr is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function factorial_ptr +[eva:alarm] tests/value/recursion.c:90: Warning: + accessing uninitialized left-value. assert \initialized(&res); +[eva] tests/value/recursion.c:358: Frama_C_show_each_120: [0..4294967295] +[eva:recursion] tests/value/recursion.c:101: + detected recursive call of function syracuse_ptr. +[eva] tests/value/recursion.c:101: Warning: + Using specification of function syracuse_ptr for recursive calls. + Analysis of function syracuse_ptr is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function syracuse_ptr +[eva:alarm] tests/value/recursion.c:102: Warning: + accessing uninitialized left-value. assert \initialized(&prev_res); +[eva] tests/value/recursion.c:361: Frama_C_show_each_1: [0..4294967294] +[eva:recursion] tests/value/recursion.c:117: + detected recursive call of function fibonacci_ptr. +[eva] tests/value/recursion.c:117: Warning: + Using specification of function fibonacci_ptr for recursive calls. + Analysis of function fibonacci_ptr is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function fibonacci_ptr +[eva:recursion] tests/value/recursion.c:119: + detected recursive call of function fibonacci_ptr. +[eva] tests/value/recursion.c:119: Warning: + Using specification of function fibonacci_ptr for recursive calls. + Analysis of function fibonacci_ptr is thus incomplete and its soundness + relies on the written specification. +[eva:alarm] tests/value/recursion.c:120: Warning: + accessing uninitialized left-value. assert \initialized(&x); +[eva:alarm] tests/value/recursion.c:120: Warning: + accessing uninitialized left-value. assert \initialized(&y); +[eva] tests/value/recursion.c:364: Frama_C_show_each_89: [0..4294967295] +[eva:recursion] tests/value/recursion.c:137: + detected recursive call of function sum_and_fact. +[eva] tests/value/recursion.c:137: Warning: + Using specification of function sum_and_fact for recursive calls. + Analysis of function sum_and_fact is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function sum_and_fact +[eva:alarm] tests/value/recursion.c:128: Warning: + function sum_and_fact: postcondition got status unknown. +[eva:alarm] tests/value/recursion.c:129: Warning: + function sum_and_fact: postcondition got status unknown. +[eva] tests/value/recursion.c:368: + Frama_C_show_each_36_40320: {36}, [0..4294967288],0%8 +[eva:recursion] tests/value/recursion.c:161: + detected recursive call of function odd. +[eva] tests/value/recursion.c:161: Warning: + Using specification of function odd for recursive calls. + Analysis of function odd is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function odd +[eva:alarm] tests/value/recursion.c:149: Warning: + function odd: postcondition got status unknown. +[eva] tests/value/recursion.c:373: Frama_C_show_each_1: {1}, {1} +[eva] tests/value/recursion.c:376: Frama_C_show_each_0: {0}, {0} +[eva:recursion] tests/value/recursion.c:183: + detected recursive call of function odd_ptr. +[eva] tests/value/recursion.c:183: Warning: + Using specification of function odd_ptr for recursive calls. + Analysis of function odd_ptr is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function odd_ptr +[eva:alarm] tests/value/recursion.c:167: Warning: + function odd_ptr: postcondition got status unknown. +[eva:alarm] tests/value/recursion.c:184: Warning: + accessing uninitialized left-value. assert \initialized(&y); +[eva:alarm] tests/value/recursion.c:179: Warning: + function even_ptr: postcondition got status unknown. +[eva:recursion] tests/value/recursion.c:171: + detected recursive call of function even_ptr. +[eva] tests/value/recursion.c:379: Frama_C_show_each_1: {1}, {1} +[eva] tests/value/recursion.c:382: Frama_C_show_each_0: {0}, {0} +[eva] using specification for function Frama_C_interval +[eva] tests/value/recursion.c:388: Frama_C_show_each_6_66: [6..66] +[eva] tests/value/recursion.c:391: Frama_C_show_each_6_66: [6..66] +[eva] tests/value/recursion.c:394: Frama_C_show_each_2_89: [0..4294967295] +[eva] tests/value/recursion.c:397: Frama_C_show_each_2_89: [0..4294967295] +[eva:alarm] tests/value/recursion.c:222: Warning: + function fill_array: precondition got status invalid. +[eva:alarm] tests/value/recursion.c:226: Warning: + function fill_array: precondition got status unknown. +[eva:recursion] tests/value/recursion.c:200: + detected recursive call of function fill_array. +[eva] tests/value/recursion.c:200: Warning: + Using specification of function fill_array for recursive calls. + Analysis of function fill_array is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function fill_array +[eva:alarm] tests/value/recursion.c:200: Warning: + function fill_array: precondition got status unknown. +[eva:alarm] tests/value/recursion.c:194: Warning: + function fill_array: postcondition got status unknown. +[eva:alarm] tests/value/recursion.c:228: Warning: + function binary_search: precondition \initialized(data + (start .. end)) got status unknown. +[eva:recursion] tests/value/recursion.c:214: + detected recursive call of function binary_search. +[eva] tests/value/recursion.c:214: Warning: + Using specification of function binary_search for recursive calls. + Analysis of function binary_search is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function binary_search +[eva:recursion] tests/value/recursion.c:216: + detected recursive call of function binary_search. +[eva] tests/value/recursion.c:216: Warning: + Using specification of function binary_search for recursive calls. + Analysis of function binary_search is thus incomplete and its soundness + relies on the written specification. +[eva] tests/value/recursion.c:229: + Frama_C_show_each_3: [-2147483648..2147483647] +[eva] tests/value/recursion.c:231: + Frama_C_show_each_12: [-2147483648..2147483647] +[eva] tests/value/recursion.c:233: + Frama_C_show_each_minus1: [-2147483648..2147483647] +[eva] tests/value/recursion.c:238: + Frama_C_show_each_7_11: [-2147483648..2147483647] +[eva] tests/value/recursion.c:241: + Frama_C_show_each_minus_1_15: [-2147483648..2147483647] +[eva:recursion] tests/value/recursion.c:252: + detected recursive call of function alarm. +[eva] tests/value/recursion.c:252: Warning: + Using specification of function alarm for recursive calls. + Analysis of function alarm is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function alarm +[eva:alarm] tests/value/recursion.c:247: Warning: + function alarm: postcondition got status unknown. +[eva:alarm] tests/value/recursion.c:252: Warning: + signed overflow. assert i * tmp ≤ 2147483647; + (tmp from alarm(i - 1)) +[eva] tests/value/recursion.c:406: + Frama_C_show_each_unreachable: [20..2147483640],0%20 +[eva:recursion] tests/value/recursion.c:261: + detected recursive call of function precond. +[eva] tests/value/recursion.c:261: Warning: + Using specification of function precond for recursive calls. + Analysis of function precond is thus incomplete and its soundness + relies on the written specification. +[inout] Warning: no assigns clauses for function precond. + Results will be imprecise. +[eva] using specification for function precond +[eva] tests/value/recursion.c:261: Warning: + Cannot handle empty assigns clause. Assuming assigns \nothing: be aware this is probably incorrect. +[eva:recursion] tests/value/recursion.c:276: + detected recursive call of function escaping_local. +[eva] tests/value/recursion.c:276: Warning: + Using specification of function escaping_local for recursive calls. + Analysis of function escaping_local is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function escaping_local +[eva:alarm] tests/value/recursion.c:278: Warning: + out of bounds write. assert \valid(p); +[eva] tests/value/recursion.c:279: Frama_C_show_each_1: {5} +[eva:locals-escaping] tests/value/recursion.c:277: Warning: + locals {x} escaping the scope of a block of escaping_local through p +[eva:recursion] tests/value/recursion.c:291: + detected recursive call of function escaping_formal. +[eva] tests/value/recursion.c:291: Warning: + Using specification of function escaping_formal for recursive calls. + Analysis of function escaping_formal is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function escaping_formal +[eva:alarm] tests/value/recursion.c:293: Warning: + out of bounds write. assert \valid(p); +[eva] tests/value/recursion.c:294: Frama_C_show_each_1: {5} +[eva:locals-escaping] tests/value/recursion.c:411: Warning: + locals {x} escaping the scope of escaping_formal through p +[eva:recursion] tests/value/recursion.c:307: + detected recursive call of function escaping_stack. +[eva] tests/value/recursion.c:307: Warning: + Using specification of function escaping_stack for recursive calls. + Analysis of function escaping_stack is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function escaping_stack +[eva:alarm] tests/value/recursion.c:309: Warning: + out of bounds write. assert \valid(p); +[eva] tests/value/recursion.c:310: Frama_C_show_each_1_2: {5} +[eva:locals-escaping] tests/value/recursion.c:308: Warning: + locals {x} escaping the scope of a block of escaping_stack through p +[eva:recursion] tests/value/recursion.c:323: + detected recursive call of function decr. +[eva] tests/value/recursion.c:323: Warning: + Using specification of function decr for recursive calls. + Analysis of function decr is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function decr +[eva] done for function main +[eva] ====== VALUES COMPUTED ====== +[eva:final-states] Values at end of function alarm: + res ∈ [10..2147483647] + __retres ∈ [10..2147483647] +[eva:final-states] Values at end of function decr: + +[eva:final-states] Values at end of function bug_memexec: + +[eva:final-states] Values at end of function escaping_formal: + p ∈ {{ NULL + [--..--] ; &x }} x ∈ [--..--] - c ∈ [--..--] - s ∈ [--..--] - pg ∈ {{ NULL ; &S_pg[0] }} - S_pg[0..1] ∈ [--..--] -[eva] computing for function ff <- main. - Called from tests/value/recursion.i:68. -[eva] tests/value/recursion.i:9: User Error: - detected recursive call (ff <- ff :: tests/value/recursion.i:68 <- main) - Use -eva-ignore-recursive-calls to ignore (beware this will make the analysis - unsound) -[eva] User Error: Degeneration occurred: - results are not correct for lines of code that can be reached from the degeneration point. -[eva] User Error: Deferred error message was emitted during execution. See above messages for more information. -[kernel] Plug-in eva aborted: invalid user input. +[eva:final-states] Values at end of function escaping_local: + p ∈ [--..--] or ESCAPINGADDR +[eva:final-states] Values at end of function escaping_stack: + p ∈ + {{ garbled mix of &{a} + (origin: Library function {tests/value/recursion.c:307}) }} or ESCAPINGADDR + a ∈ [--..--] +[eva:final-states] Values at end of function even: + __retres ∈ UNINITIALIZED + __retres ∈ {0; 1} +[eva:final-states] Values at end of function even_ptr: + x ∈ [--..--] + b ∈ {0; 1} +[eva:final-states] Values at end of function factorial: + res ∈ [--..--] + __retres ∈ [--..--] +[eva:final-states] Values at end of function factorial_ptr: + y ∈ [--..--] +[eva:final-states] Values at end of function fill_array: + array[0] ∈ {0} + [1..10] ∈ [--..--] + [11..15] ∈ [--..--] or UNINITIALIZED +[eva:final-states] Values at end of function five: + __retres ∈ {5} +[eva:final-states] Values at end of function odd: + __retres ∈ {0; 1} + __retres ∈ UNINITIALIZED +[eva:final-states] Values at end of function odd_ptr: + y ∈ [--..--] + a ∈ [--..--] +[eva:final-states] Values at end of function precond: +Cannot filter: dumping raw memory (including unchanged variables) + Frama_C_entropy_source ∈ [--..--] + nondet ∈ [--..--] + x ∈ {1} + y ∈ {-6} + p ∈ {0} + a ∈ {0} + b ∈ {0} + x ∈ [10..20] + y ∈ [10..2147483647] + tmp ∈ [3..11] + tmp_0 ∈ [10..20] + tmp_1 ∈ [10..2147483647] +[eva:final-states] Values at end of function sum: + res ∈ [6..91] + __retres ∈ [6..91] +[eva:final-states] Values at end of function sum_and_fact: + x ∈ {36} + __retres ∈ [0..4294967288],0%8 +[eva:final-states] Values at end of function sum_ptr: + y ∈ [6..91] +[eva:final-states] Values at end of function syracuse: + __retres ∈ [0..4294967294] +[eva:final-states] Values at end of function syracuse_ptr: + y ∈ [0..4294967294] +[eva:final-states] Values at end of function binary_search: + mid ∈ {7} + __retres ∈ [--..--] +[eva:final-states] Values at end of function fibonacci: + __retres ∈ [--..--] +[eva:final-states] Values at end of function fibonacci_ptr: + y ∈ [--..--] +[eva:final-states] Values at end of function test_array: + Frama_C_entropy_source ∈ [--..--] + array[0] ∈ {0} + [1..9] ∈ [--..--] + [10] ∈ {10} + [11..15] ∈ [--..--] + i ∈ [--..--] + j ∈ [7..18] + end ∈ {10; 11; 12; 13; 14; 15; 16} +[eva:final-states] Values at end of function main: +Cannot filter: dumping raw memory (including unchanged variables) + Frama_C_entropy_source ∈ [--..--] + nondet ∈ [--..--] + p ∈ + {{ garbled mix of &{a} + (origin: Library function {tests/value/recursion.c:307}) }} or ESCAPINGADDR + a ∈ [--..--] + b ∈ {0} + x ∈ [10..20] + y ∈ [10..2147483647] + tmp ∈ [3..11] + tmp_0 ∈ [10..20] + tmp_1 ∈ [10..2147483647] +[from] Computing for function alarm +[from] Computing for function alarm <-alarm +[from] Done for function alarm +[from] Done for function alarm +[from] Computing for function decr +[from] Computing for function decr <-decr +[from] Done for function decr +[from] Done for function decr +[from] Computing for function bug_memexec +[from] Done for function bug_memexec +[from] Computing for function escaping_formal +[from] Computing for function escaping_formal <-escaping_formal +[from] Done for function escaping_formal +[from] Done for function escaping_formal +[from] Computing for function escaping_local +[from] Computing for function escaping_local <-escaping_local +[from] Done for function escaping_local +[from] Done for function escaping_local +[from] Computing for function escaping_stack +[from] Computing for function escaping_stack <-escaping_stack +[from] Done for function escaping_stack +[from] Done for function escaping_stack +[from] Computing for function even +[from] Computing for function odd <-even +[from] Computing for function even <-odd <-even +[from] Done for function even +[from] Done for function odd +[from] Done for function even +[from] Computing for function even_ptr +[from] Computing for function odd_ptr <-even_ptr +[from] Computing for function even_ptr <-odd_ptr <-even_ptr +[from] Done for function even_ptr +[from] Done for function odd_ptr +[from] Done for function even_ptr +[from] Computing for function factorial +[from] Computing for function factorial <-factorial +[from] Done for function factorial +[from] Done for function factorial +[from] Computing for function factorial_ptr +[from] Computing for function factorial_ptr <-factorial_ptr +[from] Done for function factorial_ptr +[from] Done for function factorial_ptr +[from] Computing for function fill_array +[from] Computing for function fill_array <-fill_array +[from] Done for function fill_array +[from] Done for function fill_array +[from] Computing for function five +[from] Computing for function five <-five +[from] Done for function five +[from] Done for function five +[from] Computing for function precond +[from] Computing for function precond <-precond +[from] Done for function precond +[from] Done for function precond +[from] Computing for function sum +[from] Computing for function sum <-sum +[from] Done for function sum +[from] Done for function sum +[from] Computing for function sum_and_fact +[from] Computing for function sum_and_fact <-sum_and_fact +[from] Done for function sum_and_fact +[from] Done for function sum_and_fact +[from] Computing for function sum_ptr +[from] Computing for function sum_ptr <-sum_ptr +[from] Done for function sum_ptr +[from] Done for function sum_ptr +[from] Computing for function syracuse +[from] Computing for function syracuse <-syracuse +[from] Done for function syracuse +[from] Done for function syracuse +[from] Computing for function syracuse_ptr +[from] Computing for function syracuse_ptr <-syracuse_ptr +[from] Done for function syracuse_ptr +[from] Done for function syracuse_ptr +[from] Computing for function binary_search +[from] Computing for function binary_search <-binary_search +[from] Done for function binary_search +[from] Done for function binary_search +[from] Computing for function fibonacci +[from] Computing for function fibonacci <-fibonacci +[from] Done for function fibonacci +[from] Done for function fibonacci +[from] Computing for function fibonacci_ptr +[from] Computing for function fibonacci_ptr <-fibonacci_ptr +[from] Done for function fibonacci_ptr +[from] Done for function fibonacci_ptr +[from] Computing for function test_array +[from] Computing for function Frama_C_interval <-test_array +[from] Done for function Frama_C_interval +[from] Done for function test_array +[from] Computing for function main +[from] Done for function main +[from] ====== DEPENDENCIES COMPUTED ====== + These dependencies hold at termination for the executions that terminate: +[from] Function Frama_C_interval: + Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) + \result FROM Frama_C_entropy_source; min; max +[from] Function alarm: + res FROM i + tmp FROM i + __retres FROM i + \result FROM i +[from] Function decr: + NO EFFECTS +[from] Function bug_memexec: + NO EFFECTS +[from] Function escaping_formal: + p FROM count + x FROM nondet; count (and SELF) +[from] Function escaping_local: + p FROM count +[from] Function escaping_stack: + p FROM count; q + a FROM nondet; count; q (and SELF) +[from] Function even: + __retres FROM n + __retres FROM n + \result FROM n +[from] Function even_ptr: + x FROM n; result (and SELF) + a FROM n (and SELF) + b FROM n; result (and SELF) +[from] Function factorial: + res FROM i + tmp FROM i + __retres FROM i + \result FROM i +[from] Function factorial_ptr: + y FROM p_0; result; x +[from] Function fill_array: + array{[0]; [10]} FROM data; start; end (and SELF) +[from] Function five: + __retres FROM nondet + \result FROM nondet +[from] Function odd: + __retres FROM n + \result FROM n +[from] Function odd_ptr: + y FROM n; result (and SELF) + a FROM n; result (and SELF) +[from] Function precond: + y FROM x +[from] Function sum: + res FROM i + tmp FROM i + __retres FROM i + \result FROM i +[from] Function sum_and_fact: + x FROM i; sum_0 + __retres FROM i + \result FROM i +[from] Function sum_ptr: + y FROM p_0; result; x +[from] Function syracuse: + __retres FROM i + \result FROM i +[from] Function syracuse_ptr: + y FROM p_0; result; x +[from] Function binary_search: + mid FROM start; end + __retres FROM data; toFind; start; end; array[7] + \result FROM data; toFind; start; end; array[7] +[from] Function fibonacci: + __retres FROM n + \result FROM n +[from] Function fibonacci_ptr: + y FROM p_0; result; x +[from] Function test_array: + Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) +[from] Function main: + Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) + p FROM \nothing +[from] ====== END OF DEPENDENCIES ====== +[inout] Out (internal) for function alarm: + res; tmp; __retres +[inout] Inputs for function alarm: + i; res; tmp; __retres +[inout] Out (internal) for function decr: + x +[inout] Inputs for function decr: + nondet; i +[inout] Out (internal) for function bug_memexec: + \nothing +[inout] Inputs for function bug_memexec: + nondet +[inout] Out (internal) for function escaping_formal: + p; x +[inout] Inputs for function escaping_formal: + nondet; p; count; x +[inout] Out (internal) for function escaping_local: + p; x +[inout] Inputs for function escaping_local: + nondet; p; count +[inout] Out (internal) for function escaping_stack: + p; x; a +[inout] Inputs for function escaping_stack: + nondet; p; count; q +[inout] Out (internal) for function even: + tmp; tmp; __retres; __retres +[inout] Inputs for function even: + n; tmp; n; tmp; __retres; __retres +[inout] Out (internal) for function even_ptr: + x; y; b +[inout] Inputs for function even_ptr: + n; result; x; n; result; y +[inout] Out (internal) for function factorial: + res; tmp; __retres +[inout] Inputs for function factorial: + i; res; tmp; __retres +[inout] Out (internal) for function factorial_ptr: + arg; y +[inout] Inputs for function factorial_ptr: + p_0; result; res; x +[inout] Out (internal) for function fill_array: + array[0..15] +[inout] Inputs for function fill_array: + data; start; end +[inout] Out (internal) for function five: + tmp; __retres +[inout] Inputs for function five: + nondet; tmp; __retres +[inout] Out (internal) for function odd: + tmp; tmp; __retres; __retres +[inout] Inputs for function odd: + n; tmp; n; tmp; __retres; __retres +[inout] Out (internal) for function odd_ptr: + x; y; a +[inout] Inputs for function odd_ptr: + n; result; x; n; result; y +[inout] Out (internal) for function precond: + ANYTHING(origin:Unknown) +[inout] Inputs for function precond: + nondet; x +[inout] Out (internal) for function sum: + res; tmp; __retres +[inout] Inputs for function sum: + i; res; tmp; __retres +[inout] Out (internal) for function sum_and_fact: + fact; tmp_0; x; __retres +[inout] Inputs for function sum_and_fact: + i; sum_0; tmp; fact; tmp_0; __retres +[inout] Out (internal) for function sum_ptr: + arg; y +[inout] Inputs for function sum_ptr: + p_0; result; res; x +[inout] Out (internal) for function syracuse: + prev; __retres +[inout] Inputs for function syracuse: + n; i; prev; __retres +[inout] Out (internal) for function syracuse_ptr: + prev_arg; y +[inout] Inputs for function syracuse_ptr: + n; p_0; result; prev_res; x +[inout] Out (internal) for function binary_search: + mid; tmp; tmp_0; __retres +[inout] Inputs for function binary_search: + data; toFind; start; end; mid; tmp; tmp_0; array[7]; __retres +[inout] Out (internal) for function fibonacci: + x; y; __retres +[inout] Inputs for function fibonacci: + n; x; y; __retres +[inout] Out (internal) for function fibonacci_ptr: + a; y +[inout] Inputs for function fibonacci_ptr: + p_0; result; x; y; a; x +[inout] Out (internal) for function test_array: + Frama_C_entropy_source; array[0..15]; i; j; end +[inout] Inputs for function test_array: + Frama_C_entropy_source; nondet +[inout] Out (internal) for function main: + ANYTHING(origin:Unknown) +[inout] Inputs for function main: + Frama_C_entropy_source; nondet; p diff --git a/tests/value/oracle/recursion.1.res.oracle b/tests/value/oracle/recursion.1.res.oracle index 4738d12e1cca4cee88dc7dad81f2718b31e1b7ea..5fd6d46ceb18ba3e3efda9e41353d2e7da7de780 100644 --- a/tests/value/oracle/recursion.1.res.oracle +++ b/tests/value/oracle/recursion.1.res.oracle @@ -1,110 +1,514 @@ -[kernel] Parsing tests/value/recursion.i (no preprocessing) -[eva] Analyzing an incomplete application starting at main +[kernel] Parsing tests/value/recursion.c (with preprocessing) +[eva] Analyzing a complete application starting at main [eva] Computing initial state [eva] Initial state computed [eva:initial-state] Values of globals at initialization - G ∈ [--..--] - x ∈ [--..--] - c ∈ [--..--] - s ∈ [--..--] - pg ∈ {{ NULL ; &S_pg[0] }} - S_pg[0..1] ∈ [--..--] -[eva] computing for function ff <- main. - Called from tests/value/recursion.i:68. -[eva] tests/value/recursion.i:9: Warning: - recursive call during value analysis - of ff (ff <- ff :: tests/value/recursion.i:68 <- main). Assuming the call has - no effect. The analysis will be unsound. -[eva] computing for function ff <- ff <- main. - Called from tests/value/recursion.i:9. -[eva] using specification for function ff -[eva] Done for function ff -[eva] Recording results for ff -[eva] Done for function ff -[eva] computing for function g <- main. - Called from tests/value/recursion.i:69. -[eva] tests/value/recursion.i:40: Warning: - recursive call during value analysis - of g (g <- g :: tests/value/recursion.i:69 <- main). Assuming the call has - no effect. The analysis will be unsound. -[eva] computing for function g <- g <- main. - Called from tests/value/recursion.i:40. -[eva] using specification for function g -[eva] Done for function g -[eva] Recording results for g -[eva] Done for function g -[eva] computing for function h <- main. - Called from tests/value/recursion.i:71. -[eva] tests/value/recursion.i:45: Warning: - recursive call during value analysis - of h (h <- h :: tests/value/recursion.i:71 <- main). Assuming the call has - no effect. The analysis will be unsound. -[eva] computing for function h <- h <- main. - Called from tests/value/recursion.i:45. -[eva] using specification for function h -[eva] Done for function h -[eva] Recording results for h -[eva] Done for function h -[eva] tests/value/recursion.i:72: Frama_C_show_each: Bottom, Bottom -[eva] computing for function escaping_formal <- main. - Called from tests/value/recursion.i:73. -[eva] tests/value/recursion.i:73: - function escaping_formal: precondition got status valid. -[eva] tests/value/recursion.i:59: Frama_C_show_each: {{ &i }}, {10}, {0}, {10} -[eva] tests/value/recursion.i:60: Warning: - recursive call during value analysis - of escaping_formal (escaping_formal <- escaping_formal :: tests/value/recursion.i:73 <- - main). - Assuming the call has no effect. The analysis will be unsound. -[eva] tests/value/recursion.i:60: User Error: - function 'escaping_formal' (involved in a recursive call) has a formal parameter whose address is taken. Analysis may be unsound. -[eva] computing for function escaping_formal <- escaping_formal <- main. - Called from tests/value/recursion.i:60. -[eva] using specification for function escaping_formal -[eva] Done for function escaping_formal -[eva] tests/value/recursion.i:63: Frama_C_show_each: {{ &i }}, {10}, {0}, {10} -[eva] tests/value/recursion.i:55: - function escaping_formal: postcondition got status valid. -[eva] Recording results for escaping_formal -[eva] Done for function escaping_formal -[eva] computing for function f <- main. - Called from tests/value/recursion.i:74. -[eva] tests/value/recursion.i:29: Frama_C_show_each: {2}, {0} -[eva] tests/value/recursion.i:31: Warning: - recursive call during value analysis - of f (f <- f :: tests/value/recursion.i:74 <- main). Assuming the call has - no effect. The analysis will be unsound. -[eva] computing for function f <- f <- main. - Called from tests/value/recursion.i:31. -[eva] using specification for function f -[eva] Done for function f -[eva] tests/value/recursion.i:32: Frama_C_show_each: {2}, {0} -[eva] Recording results for f -[eva] Done for function f -[eva] tests/value/recursion.i:75: Frama_C_show_each: {2} -[eva:alarm] tests/value/recursion.i:76: Warning: - signed overflow. assert r.f1 + 1 ≤ 2147483647; -[eva] Recording results for main + nondet ∈ [--..--] + p ∈ {0} +[eva:recursion] tests/value/recursion.c:18: + detected recursive call of function five. +[eva] tests/value/recursion.c:18: Warning: + Using specification of function five for recursive calls of depth 20. + Analysis of function five is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function five +[eva:alarm] tests/value/recursion.c:15: Warning: + function five: postcondition got status unknown. +[eva] tests/value/recursion.c:342: Frama_C_show_each_5: {5} +[eva:recursion] tests/value/recursion.c:28: + detected recursive call of function sum. +[eva] tests/value/recursion.c:344: Frama_C_show_each_91: {91} +[eva:recursion] tests/value/recursion.c:37: + detected recursive call of function factorial. +[eva] tests/value/recursion.c:346: Frama_C_show_each_120: {120} +[eva:recursion] tests/value/recursion.c:46: + detected recursive call of function syracuse. +[eva] tests/value/recursion.c:348: Frama_C_show_each_1: {1} +[eva:recursion] tests/value/recursion.c:59: + detected recursive call of function fibonacci. +[eva:recursion] tests/value/recursion.c:60: + detected recursive call of function fibonacci. +[eva] tests/value/recursion.c:350: Frama_C_show_each_89: {89} +[eva:recursion] tests/value/recursion.c:76: + detected recursive call of function sum_ptr. +[eva] tests/value/recursion.c:355: Frama_C_show_each_91: {91} +[eva:recursion] tests/value/recursion.c:89: + detected recursive call of function factorial_ptr. +[eva] tests/value/recursion.c:358: Frama_C_show_each_120: {120} +[eva:recursion] tests/value/recursion.c:101: + detected recursive call of function syracuse_ptr. +[eva] tests/value/recursion.c:361: Frama_C_show_each_1: {1} +[eva:recursion] tests/value/recursion.c:117: + detected recursive call of function fibonacci_ptr. +[eva:recursion] tests/value/recursion.c:119: + detected recursive call of function fibonacci_ptr. +[eva] tests/value/recursion.c:364: Frama_C_show_each_89: {89} +[eva:recursion] tests/value/recursion.c:137: + detected recursive call of function sum_and_fact. +[eva] tests/value/recursion.c:368: Frama_C_show_each_36_40320: {36}, {40320} +[eva:recursion] tests/value/recursion.c:161: + detected recursive call of function odd. +[eva:recursion] tests/value/recursion.c:152: + detected recursive call of function even. +[eva] tests/value/recursion.c:373: Frama_C_show_each_1: {1}, {1} +[eva] tests/value/recursion.c:376: Frama_C_show_each_0: {0}, {0} +[eva:recursion] tests/value/recursion.c:183: + detected recursive call of function odd_ptr. +[eva:recursion] tests/value/recursion.c:171: + detected recursive call of function even_ptr. +[eva] tests/value/recursion.c:379: Frama_C_show_each_1: {1}, {1} +[eva] tests/value/recursion.c:382: Frama_C_show_each_0: {0}, {0} +[eva] using specification for function Frama_C_interval +[eva:alarm] tests/value/recursion.c:24: Warning: + function sum: postcondition got status unknown. +[eva] tests/value/recursion.c:388: Frama_C_show_each_6_66: [6..66] +[eva:alarm] tests/value/recursion.c:69: Warning: + function sum_ptr: postcondition got status unknown. +[eva] tests/value/recursion.c:391: Frama_C_show_each_6_66: [6..66] +[eva] tests/value/recursion.c:394: Frama_C_show_each_2_89: [2..89] +[eva] tests/value/recursion.c:397: Frama_C_show_each_2_89: [2..89] +[eva:alarm] tests/value/recursion.c:222: Warning: + function fill_array: precondition got status invalid. +[eva:alarm] tests/value/recursion.c:226: Warning: + function fill_array: precondition got status unknown. +[eva:recursion] tests/value/recursion.c:200: + detected recursive call of function fill_array. +[eva:alarm] tests/value/recursion.c:200: Warning: + function fill_array: precondition got status unknown. +[eva:alarm] tests/value/recursion.c:199: Warning: + out of bounds write. assert \valid(data + start); +[kernel] tests/value/recursion.c:199: Warning: + all target addresses were invalid. This path is assumed to be dead. +[eva:alarm] tests/value/recursion.c:194: Warning: + function fill_array: postcondition got status unknown. +[eva:alarm] tests/value/recursion.c:228: Warning: + function binary_search: precondition \initialized(data + (start .. end)) got status unknown. +[eva:recursion] tests/value/recursion.c:214: + detected recursive call of function binary_search. +[eva] tests/value/recursion.c:229: Frama_C_show_each_3: {3} +[eva:recursion] tests/value/recursion.c:216: + detected recursive call of function binary_search. +[eva] tests/value/recursion.c:231: Frama_C_show_each_12: {12} +[eva] tests/value/recursion.c:233: Frama_C_show_each_minus1: {-1} +[eva] tests/value/recursion.c:238: Frama_C_show_each_7_11: {7; 8; 9; 10; 11} +[eva] tests/value/recursion.c:241: Frama_C_show_each_minus_1_15: [-1..15] +[eva:recursion] tests/value/recursion.c:252: + detected recursive call of function alarm. +[eva:alarm] tests/value/recursion.c:252: Warning: + signed overflow. assert i * tmp ≤ 2147483647; + (tmp from alarm(i - 1)) +[eva:recursion] tests/value/recursion.c:261: + detected recursive call of function precond. +[eva:alarm] tests/value/recursion.c:261: Warning: + function precond: precondition got status invalid. +[eva:recursion] tests/value/recursion.c:276: + detected recursive call of function escaping_local. +[eva] tests/value/recursion.c:279: Frama_C_show_each_1: {1} +[eva:locals-escaping] tests/value/recursion.c:277: Warning: + locals {x} escaping the scope of a block of escaping_local through p +[eva:alarm] tests/value/recursion.c:278: Warning: + accessing left-value that contains escaping addresses. + assert ¬\dangling(&p); +[kernel] tests/value/recursion.c:278: Warning: + all target addresses were invalid. This path is assumed to be dead. +[eva:recursion] tests/value/recursion.c:291: + detected recursive call of function escaping_formal. +[eva] tests/value/recursion.c:294: Frama_C_show_each_1: {1} +[eva:locals-escaping] tests/value/recursion.c:291: Warning: + locals {x} escaping the scope of escaping_formal through p +[eva:alarm] tests/value/recursion.c:293: Warning: + accessing left-value that contains escaping addresses. + assert ¬\dangling(&p); +[kernel] tests/value/recursion.c:293: Warning: + all target addresses were invalid. This path is assumed to be dead. +[eva:recursion] tests/value/recursion.c:307: + detected recursive call of function escaping_stack. +[eva] tests/value/recursion.c:310: Frama_C_show_each_1_2: {1} +[eva] tests/value/recursion.c:310: Frama_C_show_each_1_2: {2} +[eva:locals-escaping] tests/value/recursion.c:308: Warning: + locals {x} escaping the scope of a block of escaping_stack through p +[eva:alarm] tests/value/recursion.c:309: Warning: + accessing left-value that contains escaping addresses. + assert ¬\dangling(&p); +[kernel] tests/value/recursion.c:309: Warning: + all target addresses were invalid. This path is assumed to be dead. +[eva:recursion] tests/value/recursion.c:323: + detected recursive call of function decr. +[eva] tests/value/recursion.c:323: Warning: + Using specification of function decr for recursive calls of depth 20. + Analysis of function decr is thus incomplete and its soundness + relies on the written specification. +[eva] using specification for function decr [eva] done for function main [eva] ====== VALUES COMPUTED ====== -[eva:final-states] Values at end of function escaping_formal: - pg ∈ {0} -[eva:final-states] Values at end of function f: - x ∈ {2} - s ∈ [--..--] -[eva:final-states] Values at end of function ff: - __retres ∈ {5} -[eva:final-states] Values at end of function g: +[eva:final-states] Values at end of function alarm: + res ∈ [2..2147483647] + __retres ∈ [1..2147483647] +[eva:final-states] Values at end of function decr: -[eva:final-states] Values at end of function h: +[eva:final-states] Values at end of function bug_memexec: +[eva:final-states] Values at end of function escaping_formal: + p ∈ {{ &x ; &\copy<x>[5] }} or ESCAPINGADDR + x ∈ {5; 16} +[eva:final-states] Values at end of function escaping_local: + p ∈ {{ &\copy<x>[5] }} or ESCAPINGADDR +[eva:final-states] Values at end of function escaping_stack: + p ∈ {{ &\copy<x>[4] }} or ESCAPINGADDR +[eva:final-states] Values at end of function even: + __retres ∈ UNINITIALIZED + __retres ∈ {0; 1} +[eva:final-states] Values at end of function even_ptr: + x ∈ {0; 1} + b ∈ {0; 1} +[eva:final-states] Values at end of function factorial: + res ∈ {2; 6; 24; 120} + __retres ∈ {1; 2; 6; 24; 120} +[eva:final-states] Values at end of function factorial_ptr: + y ∈ {91; 120} +[eva:final-states] Values at end of function fill_array: + array[0] ∈ {0} + [1] ∈ {1} + [2] ∈ {2} + [3] ∈ {3} + [4] ∈ {4} + [5] ∈ {5} + [6] ∈ {6} + [7] ∈ {7} + [8] ∈ {8} + [9] ∈ {9} + [10] ∈ {10} + [11] ∈ {11} or UNINITIALIZED + [12] ∈ {12} or UNINITIALIZED + [13] ∈ {13} or UNINITIALIZED + [14] ∈ {14} or UNINITIALIZED + [15] ∈ {15} or UNINITIALIZED +[eva:final-states] Values at end of function five: + __retres ∈ {5} +[eva:final-states] Values at end of function odd: + __retres ∈ {0; 1} + __retres ∈ UNINITIALIZED +[eva:final-states] Values at end of function odd_ptr: + y ∈ {0; 1} + a ∈ {0; 1} +[eva:final-states] Values at end of function precond: + y ∈ [-100..-6] +[eva:final-states] Values at end of function sum: + res ∈ [3..91] + __retres ∈ [1..91] +[eva:final-states] Values at end of function sum_and_fact: + x ∈ {11; 36} + __retres ∈ {1; 2; 6; 24; 120; 720; 5040; 40320} +[eva:final-states] Values at end of function sum_ptr: + y ∈ [0..91] +[eva:final-states] Values at end of function syracuse: + __retres ∈ [1..16] +[eva:final-states] Values at end of function syracuse_ptr: + y ∈ {1; 120} +[eva:final-states] Values at end of function binary_search: + mid ∈ [3..16] + __retres ∈ [-1..15] +[eva:final-states] Values at end of function fibonacci: + __retres ∈ [0..89] +[eva:final-states] Values at end of function fibonacci_ptr: + y ∈ [0..89] +[eva:final-states] Values at end of function test_array: + Frama_C_entropy_source ∈ [--..--] + array[0] ∈ {0} + [1] ∈ {1} + [2] ∈ {2} + [3] ∈ {3} + [4] ∈ {4} + [5] ∈ {5} + [6] ∈ {6} + [7] ∈ {7} + [8] ∈ {8} + [9] ∈ {9} + [10] ∈ {10} + [11] ∈ {11} + [12] ∈ {12} + [13] ∈ {13} + [14] ∈ {14} + [15] ∈ {15} + i ∈ [-1..15] + j ∈ [7..18] + end ∈ {10; 11; 12; 13; 14; 15} [eva:final-states] Values at end of function main: - G ∈ {5} - x ∈ {2} - s ∈ [--..--] - pg ∈ {0} - r.f1 ∈ [-2147483648..2147483646] - .f2 ∈ [--..--] - __retres ∈ [-2147483647..2147483647] -[eva] User Error: Deferred error message was emitted during execution. See above messages for more information. -[kernel] Plug-in eva aborted: invalid user input. + Frama_C_entropy_source ∈ [--..--] + p ∈ ESCAPINGADDR + a ∈ {0} + b ∈ {0} + x ∈ [10..20] + y ∈ [3628800..2147483647] +[from] Computing for function alarm +[from] Computing for function alarm <-alarm +[from] Done for function alarm +[from] Done for function alarm +[from] Computing for function decr +[from] Computing for function decr <-decr +[from] Done for function decr +[from] Done for function decr +[from] Computing for function bug_memexec +[from] Done for function bug_memexec +[from] Computing for function escaping_formal +[from] Computing for function escaping_formal <-escaping_formal +[from] Done for function escaping_formal +[from] Done for function escaping_formal +[from] Computing for function escaping_local +[from] Computing for function escaping_local <-escaping_local +[from] Done for function escaping_local +[from] Done for function escaping_local +[from] Computing for function escaping_stack +[from] Computing for function escaping_stack <-escaping_stack +[from] Done for function escaping_stack +[from] Done for function escaping_stack +[from] Computing for function even +[from] Computing for function odd <-even +[from] Computing for function even <-odd <-even +[from] Done for function even +[from] Done for function odd +[from] Done for function even +[from] Computing for function even_ptr +[from] Computing for function odd_ptr <-even_ptr +[from] Computing for function even_ptr <-odd_ptr <-even_ptr +[from] Done for function even_ptr +[from] Done for function odd_ptr +[from] Done for function even_ptr +[from] Computing for function factorial +[from] Computing for function factorial <-factorial +[from] Done for function factorial +[from] Done for function factorial +[from] Computing for function factorial_ptr +[from] Computing for function factorial_ptr <-factorial_ptr +[from] Done for function factorial_ptr +[from] Done for function factorial_ptr +[from] Computing for function fill_array +[from] Computing for function fill_array <-fill_array +[from] Done for function fill_array +[from] Done for function fill_array +[from] Computing for function five +[from] Computing for function five <-five +[from] Done for function five +[from] Done for function five +[from] Computing for function precond +[from] Computing for function precond <-precond +[from] Done for function precond +[from] Done for function precond +[from] Computing for function sum +[from] Computing for function sum <-sum +[from] Done for function sum +[from] Done for function sum +[from] Computing for function sum_and_fact +[from] Computing for function sum_and_fact <-sum_and_fact +[from] Done for function sum_and_fact +[from] Done for function sum_and_fact +[from] Computing for function sum_ptr +[from] Computing for function sum_ptr <-sum_ptr +[from] Done for function sum_ptr +[from] Done for function sum_ptr +[from] Computing for function syracuse +[from] Computing for function syracuse <-syracuse +[from] Done for function syracuse +[from] Done for function syracuse +[from] Computing for function syracuse_ptr +[from] Computing for function syracuse_ptr <-syracuse_ptr +[from] Done for function syracuse_ptr +[from] Done for function syracuse_ptr +[from] Computing for function binary_search +[from] Computing for function binary_search <-binary_search +[from] Done for function binary_search +[from] Done for function binary_search +[from] Computing for function fibonacci +[from] Computing for function fibonacci <-fibonacci +[from] Done for function fibonacci +[from] Done for function fibonacci +[from] Computing for function fibonacci_ptr +[from] Computing for function fibonacci_ptr <-fibonacci_ptr +[from] Done for function fibonacci_ptr +[from] Done for function fibonacci_ptr +[from] Computing for function test_array +[from] Computing for function Frama_C_interval <-test_array +[from] Done for function Frama_C_interval +[from] Done for function test_array +[from] Computing for function main +[from] Done for function main +[from] ====== DEPENDENCIES COMPUTED ====== + These dependencies hold at termination for the executions that terminate: +[from] Function Frama_C_interval: + Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) + \result FROM Frama_C_entropy_source; min; max +[from] Function alarm: + res FROM i + tmp FROM i + __retres FROM i + \result FROM i +[from] Function decr: + NO EFFECTS +[from] Function bug_memexec: + NO EFFECTS +[from] Function escaping_formal: + p FROM count (and SELF) + x FROM nondet; count (and SELF) +[from] Function escaping_local: + p FROM count (and SELF) +[from] Function escaping_stack: + p FROM count; q (and SELF) +[from] Function even: + __retres FROM n (and SELF) + __retres FROM n + \result FROM n +[from] Function even_ptr: + x FROM n; result (and SELF) + a FROM n (and SELF) + b FROM n; result (and SELF) +[from] Function factorial: + res FROM i + tmp FROM i + __retres FROM i + \result FROM i +[from] Function factorial_ptr: + y FROM p_0; result; x (and SELF) +[from] Function fill_array: + array[0..15] FROM data; start; end (and SELF) +[from] Function five: + __retres FROM nondet + \result FROM nondet +[from] Function odd: + __retres FROM n + \result FROM n +[from] Function odd_ptr: + y FROM n; result (and SELF) + a FROM n; result (and SELF) +[from] Function precond: + y FROM x +[from] Function sum: + res FROM i + tmp FROM i + __retres FROM i + \result FROM i +[from] Function sum_and_fact: + x FROM i; sum_0 (and SELF) + __retres FROM i + \result FROM i +[from] Function sum_ptr: + y FROM p_0; result; x (and SELF) +[from] Function syracuse: + __retres FROM n; i + \result FROM n; i +[from] Function syracuse_ptr: + y FROM p_0; result; x (and SELF) +[from] Function binary_search: + mid FROM start; end + __retres FROM data; toFind; start; end; array[3..15] + \result FROM data; toFind; start; end; array[3..15] +[from] Function fibonacci: + __retres FROM n + \result FROM n +[from] Function fibonacci_ptr: + y FROM p_0; result; x (and SELF) +[from] Function test_array: + Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) +[from] Function main: + Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) + p FROM \nothing (and SELF) +[from] ====== END OF DEPENDENCIES ====== +[inout] Out (internal) for function alarm: + res; tmp; __retres +[inout] Inputs for function alarm: + i; res; tmp; __retres +[inout] Out (internal) for function decr: + x +[inout] Inputs for function decr: + nondet; i +[inout] Out (internal) for function bug_memexec: + \nothing +[inout] Inputs for function bug_memexec: + nondet +[inout] Out (internal) for function escaping_formal: + p; x +[inout] Inputs for function escaping_formal: + nondet; p; count; x +[inout] Out (internal) for function escaping_local: + p; x +[inout] Inputs for function escaping_local: + nondet; p; count +[inout] Out (internal) for function escaping_stack: + p; x +[inout] Inputs for function escaping_stack: + nondet; p; count; q +[inout] Out (internal) for function even: + tmp; tmp; __retres; __retres +[inout] Inputs for function even: + n; tmp; n; tmp; __retres; __retres +[inout] Out (internal) for function even_ptr: + x; y; b +[inout] Inputs for function even_ptr: + n; result; x; n; result; y +[inout] Out (internal) for function factorial: + res; tmp; __retres +[inout] Inputs for function factorial: + i; res; tmp; __retres +[inout] Out (internal) for function factorial_ptr: + arg; y +[inout] Inputs for function factorial_ptr: + p_0; result; res; x +[inout] Out (internal) for function fill_array: + array[0..15] +[inout] Inputs for function fill_array: + data; start; end +[inout] Out (internal) for function five: + tmp; __retres +[inout] Inputs for function five: + nondet; tmp; __retres +[inout] Out (internal) for function odd: + tmp; tmp; __retres; __retres +[inout] Inputs for function odd: + n; tmp; n; tmp; __retres; __retres +[inout] Out (internal) for function odd_ptr: + x; y; a +[inout] Inputs for function odd_ptr: + n; result; x; n; result; y +[inout] Out (internal) for function precond: + y +[inout] Inputs for function precond: + nondet; x +[inout] Out (internal) for function sum: + res; tmp; __retres +[inout] Inputs for function sum: + i; res; tmp; __retres +[inout] Out (internal) for function sum_and_fact: + fact; tmp_0; x; __retres +[inout] Inputs for function sum_and_fact: + i; sum_0; tmp; fact; tmp_0; __retres +[inout] Out (internal) for function sum_ptr: + arg; y +[inout] Inputs for function sum_ptr: + p_0; result; res; x +[inout] Out (internal) for function syracuse: + prev; __retres +[inout] Inputs for function syracuse: + n; i; prev; __retres +[inout] Out (internal) for function syracuse_ptr: + prev_arg; y +[inout] Inputs for function syracuse_ptr: + n; p_0; result; prev_res; x +[inout] Out (internal) for function binary_search: + mid; tmp; tmp_0; __retres +[inout] Inputs for function binary_search: + data; toFind; start; end; mid; tmp; tmp_0; array[3..15]; __retres +[inout] Out (internal) for function fibonacci: + x; y; __retres +[inout] Inputs for function fibonacci: + n; x; y; __retres +[inout] Out (internal) for function fibonacci_ptr: + a; y +[inout] Inputs for function fibonacci_ptr: + p_0; result; x; y; a; x +[inout] Out (internal) for function test_array: + Frama_C_entropy_source; array[0..15]; i; j; end +[inout] Inputs for function test_array: + Frama_C_entropy_source; nondet +[inout] Out (internal) for function main: + Frama_C_entropy_source; p; a; b; x; y; tmp; tmp_0; tmp_1; tmp_2 +[inout] Inputs for function main: + Frama_C_entropy_source; nondet; p diff --git a/tests/value/oracle/recursion.2.res.oracle b/tests/value/oracle/recursion.2.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..c4c6916fda19c0763ef4ab50cc3d834a54df296a --- /dev/null +++ b/tests/value/oracle/recursion.2.res.oracle @@ -0,0 +1,17 @@ +[kernel] Parsing tests/value/recursion.c (with preprocessing) +[eva] Analyzing a complete application starting at main_fail +[eva] Computing initial state +[eva] Initial state computed +[eva:initial-state] Values of globals at initialization + nondet ∈ [--..--] + p ∈ {0} +[eva:recursion] tests/value/recursion.c:422: + detected recursive call of function sum_nospec. +[eva] tests/value/recursion.c:429: Frama_C_show_each_10: {10} +[eva] tests/value/recursion.c:434: Frama_C_show_each_36: {36} +[eva] using specification for function Frama_C_interval +[eva] tests/value/recursion.c:422: User Error: + Recursive call to sum_nospec without a specification. Try to increase + the -eva-unroll-recursive-calls parameter or write a specification + for function sum_nospec. +[kernel] Plug-in eva aborted: invalid user input. diff --git a/tests/value/oracle/recursion2.res.oracle b/tests/value/oracle/recursion2.res.oracle deleted file mode 100644 index 37b6e009a2a68a864ce6ca86744f97e5a6e2ef92..0000000000000000000000000000000000000000 --- a/tests/value/oracle/recursion2.res.oracle +++ /dev/null @@ -1,67 +0,0 @@ -[kernel] Parsing tests/value/recursion2.i (no preprocessing) -[eva] Analyzing a complete application starting at main -[eva] Computing initial state -[eva] Initial state computed -[eva:initial-state] Values of globals at initialization - x ∈ {0} - y ∈ {0} -[eva] computing for function h2 <- main. - Called from tests/value/recursion2.i:21. -[eva] computing for function h1 <- h2 <- main. - Called from tests/value/recursion2.i:17. -[eva] Recording results for h1 -[eva] Done for function h1 -[eva] Recording results for h2 -[eva] Done for function h2 -[eva] computing for function h1 <- main. - Called from tests/value/recursion2.i:22. -[eva] computing for function h2 <- h1 <- main. - Called from tests/value/recursion2.i:12. -[eva] Recording results for h2 -[eva] Done for function h2 -[eva] Recording results for h1 -[eva] Done for function h1 -[eva] Recording results for main -[eva] done for function main -[eva] ====== VALUES COMPUTED ====== -[eva:final-states] Values at end of function h1: - r ∈ {0} - q ∈ {0} -[eva:final-states] Values at end of function h2: - r ∈ {0} - q ∈ {0} -[eva:final-states] Values at end of function main: - -[inout] Out (internal) for function h1: - r; q -[inout] Inputs for function h1: - x; y; i; j -[inout] InOut (internal) for function h1: - Operational inputs: - x; y; i - Operational inputs on termination: - x; y; i - Sure outputs: - r -[inout] Out (internal) for function h2: - r; q -[inout] Inputs for function h2: - x; y; i; j -[inout] InOut (internal) for function h2: - Operational inputs: - x; y; j - Operational inputs on termination: - x; y; j - Sure outputs: - q -[inout] Out (internal) for function main: - \nothing -[inout] Inputs for function main: - x; y -[inout] InOut (internal) for function main: - Operational inputs: - x; y - Operational inputs on termination: - x; y - Sure outputs: - \nothing diff --git a/tests/value/oracle_apron/recursion.0.res.oracle b/tests/value/oracle_apron/recursion.0.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..424fb0f10c57946bd4a9bf10e95994d708e89a4a --- /dev/null +++ b/tests/value/oracle_apron/recursion.0.res.oracle @@ -0,0 +1,628 @@ +10,632c10,12 +< [eva] tests/value/recursion.c:18: Warning: +< Using specification of function five for recursive calls. +< Analysis of function five is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function five +< [eva:alarm] tests/value/recursion.c:15: Warning: +< function five: postcondition got status unknown. +< [eva] tests/value/recursion.c:342: Frama_C_show_each_5: {5} +< [eva:recursion] tests/value/recursion.c:28: +< detected recursive call of function sum. +< [eva] tests/value/recursion.c:28: Warning: +< Using specification of function sum for recursive calls. +< Analysis of function sum is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function sum +< [eva:alarm] tests/value/recursion.c:24: Warning: +< function sum: postcondition got status unknown. +< [eva] tests/value/recursion.c:344: Frama_C_show_each_91: {91} +< [eva:recursion] tests/value/recursion.c:37: +< detected recursive call of function factorial. +< [eva] tests/value/recursion.c:37: Warning: +< Using specification of function factorial for recursive calls. +< Analysis of function factorial is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function factorial +< [eva] tests/value/recursion.c:346: Frama_C_show_each_120: [0..4294967295] +< [eva:recursion] tests/value/recursion.c:46: +< detected recursive call of function syracuse. +< [eva] tests/value/recursion.c:46: Warning: +< Using specification of function syracuse for recursive calls. +< Analysis of function syracuse is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function syracuse +< [eva] tests/value/recursion.c:348: Frama_C_show_each_1: [0..4294967294] +< [eva:recursion] tests/value/recursion.c:59: +< detected recursive call of function fibonacci. +< [eva] tests/value/recursion.c:59: Warning: +< Using specification of function fibonacci for recursive calls. +< Analysis of function fibonacci is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function fibonacci +< [eva:recursion] tests/value/recursion.c:60: +< detected recursive call of function fibonacci. +< [eva] tests/value/recursion.c:60: Warning: +< Using specification of function fibonacci for recursive calls. +< Analysis of function fibonacci is thus incomplete and its soundness +< relies on the written specification. +< [eva] tests/value/recursion.c:350: Frama_C_show_each_89: [0..4294967295] +< [eva:recursion] tests/value/recursion.c:76: +< detected recursive call of function sum_ptr. +< [eva] tests/value/recursion.c:76: Warning: +< Using specification of function sum_ptr for recursive calls. +< Analysis of function sum_ptr is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function sum_ptr +< [eva:alarm] tests/value/recursion.c:68: Warning: +< function sum_ptr: postcondition got status unknown. +< [eva:alarm] tests/value/recursion.c:69: Warning: +< function sum_ptr: postcondition got status unknown. +< [eva] tests/value/recursion.c:355: Frama_C_show_each_91: {91} +< [eva:recursion] tests/value/recursion.c:89: +< detected recursive call of function factorial_ptr. +< [eva] tests/value/recursion.c:89: Warning: +< Using specification of function factorial_ptr for recursive calls. +< Analysis of function factorial_ptr is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function factorial_ptr +< [eva:alarm] tests/value/recursion.c:90: Warning: +< accessing uninitialized left-value. assert \initialized(&res); +< [eva] tests/value/recursion.c:358: Frama_C_show_each_120: [0..4294967295] +< [eva:recursion] tests/value/recursion.c:101: +< detected recursive call of function syracuse_ptr. +< [eva] tests/value/recursion.c:101: Warning: +< Using specification of function syracuse_ptr for recursive calls. +< Analysis of function syracuse_ptr is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function syracuse_ptr +< [eva:alarm] tests/value/recursion.c:102: Warning: +< accessing uninitialized left-value. assert \initialized(&prev_res); +< [eva] tests/value/recursion.c:361: Frama_C_show_each_1: [0..4294967294] +< [eva:recursion] tests/value/recursion.c:117: +< detected recursive call of function fibonacci_ptr. +< [eva] tests/value/recursion.c:117: Warning: +< Using specification of function fibonacci_ptr for recursive calls. +< Analysis of function fibonacci_ptr is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function fibonacci_ptr +< [eva:recursion] tests/value/recursion.c:119: +< detected recursive call of function fibonacci_ptr. +< [eva] tests/value/recursion.c:119: Warning: +< Using specification of function fibonacci_ptr for recursive calls. +< Analysis of function fibonacci_ptr is thus incomplete and its soundness +< relies on the written specification. +< [eva:alarm] tests/value/recursion.c:120: Warning: +< accessing uninitialized left-value. assert \initialized(&x); +< [eva:alarm] tests/value/recursion.c:120: Warning: +< accessing uninitialized left-value. assert \initialized(&y); +< [eva] tests/value/recursion.c:364: Frama_C_show_each_89: [0..4294967295] +< [eva:recursion] tests/value/recursion.c:137: +< detected recursive call of function sum_and_fact. +< [eva] tests/value/recursion.c:137: Warning: +< Using specification of function sum_and_fact for recursive calls. +< Analysis of function sum_and_fact is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function sum_and_fact +< [eva:alarm] tests/value/recursion.c:128: Warning: +< function sum_and_fact: postcondition got status unknown. +< [eva:alarm] tests/value/recursion.c:129: Warning: +< function sum_and_fact: postcondition got status unknown. +< [eva] tests/value/recursion.c:368: +< Frama_C_show_each_36_40320: {36}, [0..4294967288],0%8 +< [eva:recursion] tests/value/recursion.c:161: +< detected recursive call of function odd. +< [eva] tests/value/recursion.c:161: Warning: +< Using specification of function odd for recursive calls. +< Analysis of function odd is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function odd +< [eva:alarm] tests/value/recursion.c:149: Warning: +< function odd: postcondition got status unknown. +< [eva] tests/value/recursion.c:373: Frama_C_show_each_1: {1}, {1} +< [eva] tests/value/recursion.c:376: Frama_C_show_each_0: {0}, {0} +< [eva:recursion] tests/value/recursion.c:183: +< detected recursive call of function odd_ptr. +< [eva] tests/value/recursion.c:183: Warning: +< Using specification of function odd_ptr for recursive calls. +< Analysis of function odd_ptr is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function odd_ptr +< [eva:alarm] tests/value/recursion.c:167: Warning: +< function odd_ptr: postcondition got status unknown. +< [eva:alarm] tests/value/recursion.c:184: Warning: +< accessing uninitialized left-value. assert \initialized(&y); +< [eva:alarm] tests/value/recursion.c:179: Warning: +< function even_ptr: postcondition got status unknown. +< [eva:recursion] tests/value/recursion.c:171: +< detected recursive call of function even_ptr. +< [eva] tests/value/recursion.c:379: Frama_C_show_each_1: {1}, {1} +< [eva] tests/value/recursion.c:382: Frama_C_show_each_0: {0}, {0} +< [eva] using specification for function Frama_C_interval +< [eva] tests/value/recursion.c:388: Frama_C_show_each_6_66: [6..66] +< [eva] tests/value/recursion.c:391: Frama_C_show_each_6_66: [6..66] +< [eva] tests/value/recursion.c:394: Frama_C_show_each_2_89: [0..4294967295] +< [eva] tests/value/recursion.c:397: Frama_C_show_each_2_89: [0..4294967295] +< [eva:alarm] tests/value/recursion.c:222: Warning: +< function fill_array: precondition got status invalid. +< [eva:alarm] tests/value/recursion.c:226: Warning: +< function fill_array: precondition got status unknown. +< [eva:recursion] tests/value/recursion.c:200: +< detected recursive call of function fill_array. +< [eva] tests/value/recursion.c:200: Warning: +< Using specification of function fill_array for recursive calls. +< Analysis of function fill_array is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function fill_array +< [eva:alarm] tests/value/recursion.c:200: Warning: +< function fill_array: precondition got status unknown. +< [eva:alarm] tests/value/recursion.c:194: Warning: +< function fill_array: postcondition got status unknown. +< [eva:alarm] tests/value/recursion.c:228: Warning: +< function binary_search: precondition \initialized(data + (start .. end)) got status unknown. +< [eva:recursion] tests/value/recursion.c:214: +< detected recursive call of function binary_search. +< [eva] tests/value/recursion.c:214: Warning: +< Using specification of function binary_search for recursive calls. +< Analysis of function binary_search is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function binary_search +< [eva:recursion] tests/value/recursion.c:216: +< detected recursive call of function binary_search. +< [eva] tests/value/recursion.c:216: Warning: +< Using specification of function binary_search for recursive calls. +< Analysis of function binary_search is thus incomplete and its soundness +< relies on the written specification. +< [eva] tests/value/recursion.c:229: +< Frama_C_show_each_3: [-2147483648..2147483647] +< [eva] tests/value/recursion.c:231: +< Frama_C_show_each_12: [-2147483648..2147483647] +< [eva] tests/value/recursion.c:233: +< Frama_C_show_each_minus1: [-2147483648..2147483647] +< [eva] tests/value/recursion.c:238: +< Frama_C_show_each_7_11: [-2147483648..2147483647] +< [eva] tests/value/recursion.c:241: +< Frama_C_show_each_minus_1_15: [-2147483648..2147483647] +< [eva:recursion] tests/value/recursion.c:252: +< detected recursive call of function alarm. +< [eva] tests/value/recursion.c:252: Warning: +< Using specification of function alarm for recursive calls. +< Analysis of function alarm is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function alarm +< [eva:alarm] tests/value/recursion.c:247: Warning: +< function alarm: postcondition got status unknown. +< [eva:alarm] tests/value/recursion.c:252: Warning: +< signed overflow. assert i * tmp ≤ 2147483647; +< (tmp from alarm(i - 1)) +< [eva] tests/value/recursion.c:406: +< Frama_C_show_each_unreachable: [20..2147483640],0%20 +< [eva:recursion] tests/value/recursion.c:261: +< detected recursive call of function precond. +< [eva] tests/value/recursion.c:261: Warning: +< Using specification of function precond for recursive calls. +< Analysis of function precond is thus incomplete and its soundness +< relies on the written specification. +< [inout] Warning: no assigns clauses for function precond. +< Results will be imprecise. +< [eva] using specification for function precond +< [eva] tests/value/recursion.c:261: Warning: +< Cannot handle empty assigns clause. Assuming assigns \nothing: be aware this is probably incorrect. +< [eva:recursion] tests/value/recursion.c:276: +< detected recursive call of function escaping_local. +< [eva] tests/value/recursion.c:276: Warning: +< Using specification of function escaping_local for recursive calls. +< Analysis of function escaping_local is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function escaping_local +< [eva:alarm] tests/value/recursion.c:278: Warning: +< out of bounds write. assert \valid(p); +< [eva] tests/value/recursion.c:279: Frama_C_show_each_1: {5} +< [eva:locals-escaping] tests/value/recursion.c:277: Warning: +< locals {x} escaping the scope of a block of escaping_local through p +< [eva:recursion] tests/value/recursion.c:291: +< detected recursive call of function escaping_formal. +< [eva] tests/value/recursion.c:291: Warning: +< Using specification of function escaping_formal for recursive calls. +< Analysis of function escaping_formal is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function escaping_formal +< [eva:alarm] tests/value/recursion.c:293: Warning: +< out of bounds write. assert \valid(p); +< [eva] tests/value/recursion.c:294: Frama_C_show_each_1: {5} +< [eva:locals-escaping] tests/value/recursion.c:411: Warning: +< locals {x} escaping the scope of escaping_formal through p +< [eva:recursion] tests/value/recursion.c:307: +< detected recursive call of function escaping_stack. +< [eva] tests/value/recursion.c:307: Warning: +< Using specification of function escaping_stack for recursive calls. +< Analysis of function escaping_stack is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function escaping_stack +< [eva:alarm] tests/value/recursion.c:309: Warning: +< out of bounds write. assert \valid(p); +< [eva] tests/value/recursion.c:310: Frama_C_show_each_1_2: {5} +< [eva:locals-escaping] tests/value/recursion.c:308: Warning: +< locals {x} escaping the scope of a block of escaping_stack through p +< [eva:recursion] tests/value/recursion.c:323: +< detected recursive call of function decr. +< [eva] tests/value/recursion.c:323: Warning: +< Using specification of function decr for recursive calls. +< Analysis of function decr is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function decr +< [eva] done for function main +< [eva] ====== VALUES COMPUTED ====== +< [eva:final-states] Values at end of function alarm: +< res ∈ [10..2147483647] +< __retres ∈ [10..2147483647] +< [eva:final-states] Values at end of function decr: +< +< [eva:final-states] Values at end of function bug_memexec: +< +< [eva:final-states] Values at end of function escaping_formal: +< p ∈ {{ NULL + [--..--] ; &x }} +< x ∈ [--..--] +< [eva:final-states] Values at end of function escaping_local: +< p ∈ [--..--] or ESCAPINGADDR +< [eva:final-states] Values at end of function escaping_stack: +< p ∈ +< {{ garbled mix of &{a} +< (origin: Library function {tests/value/recursion.c:307}) }} or ESCAPINGADDR +< a ∈ [--..--] +< [eva:final-states] Values at end of function even: +< __retres ∈ UNINITIALIZED +< __retres ∈ {0; 1} +< [eva:final-states] Values at end of function even_ptr: +< x ∈ [--..--] +< b ∈ {0; 1} +< [eva:final-states] Values at end of function factorial: +< res ∈ [--..--] +< __retres ∈ [--..--] +< [eva:final-states] Values at end of function factorial_ptr: +< y ∈ [--..--] +< [eva:final-states] Values at end of function fill_array: +< array[0] ∈ {0} +< [1..10] ∈ [--..--] +< [11..15] ∈ [--..--] or UNINITIALIZED +< [eva:final-states] Values at end of function five: +< __retres ∈ {5} +< [eva:final-states] Values at end of function odd: +< __retres ∈ {0; 1} +< __retres ∈ UNINITIALIZED +< [eva:final-states] Values at end of function odd_ptr: +< y ∈ [--..--] +< a ∈ [--..--] +< [eva:final-states] Values at end of function precond: +< Cannot filter: dumping raw memory (including unchanged variables) +< Frama_C_entropy_source ∈ [--..--] +< nondet ∈ [--..--] +< x ∈ {1} +< y ∈ {-6} +< p ∈ {0} +< a ∈ {0} +< b ∈ {0} +< x ∈ [10..20] +< y ∈ [10..2147483647] +< tmp ∈ [3..11] +< tmp_0 ∈ [10..20] +< tmp_1 ∈ [10..2147483647] +< [eva:final-states] Values at end of function sum: +< res ∈ [6..91] +< __retres ∈ [6..91] +< [eva:final-states] Values at end of function sum_and_fact: +< x ∈ {36} +< __retres ∈ [0..4294967288],0%8 +< [eva:final-states] Values at end of function sum_ptr: +< y ∈ [6..91] +< [eva:final-states] Values at end of function syracuse: +< __retres ∈ [0..4294967294] +< [eva:final-states] Values at end of function syracuse_ptr: +< y ∈ [0..4294967294] +< [eva:final-states] Values at end of function binary_search: +< mid ∈ {7} +< __retres ∈ [--..--] +< [eva:final-states] Values at end of function fibonacci: +< __retres ∈ [--..--] +< [eva:final-states] Values at end of function fibonacci_ptr: +< y ∈ [--..--] +< [eva:final-states] Values at end of function test_array: +< Frama_C_entropy_source ∈ [--..--] +< array[0] ∈ {0} +< [1..9] ∈ [--..--] +< [10] ∈ {10} +< [11..15] ∈ [--..--] +< i ∈ [--..--] +< j ∈ [7..18] +< end ∈ {10; 11; 12; 13; 14; 15; 16} +< [eva:final-states] Values at end of function main: +< Cannot filter: dumping raw memory (including unchanged variables) +< Frama_C_entropy_source ∈ [--..--] +< nondet ∈ [--..--] +< p ∈ +< {{ garbled mix of &{a} +< (origin: Library function {tests/value/recursion.c:307}) }} or ESCAPINGADDR +< a ∈ [--..--] +< b ∈ {0} +< x ∈ [10..20] +< y ∈ [10..2147483647] +< tmp ∈ [3..11] +< tmp_0 ∈ [10..20] +< tmp_1 ∈ [10..2147483647] +< [from] Computing for function alarm +< [from] Computing for function alarm <-alarm +< [from] Done for function alarm +< [from] Done for function alarm +< [from] Computing for function decr +< [from] Computing for function decr <-decr +< [from] Done for function decr +< [from] Done for function decr +< [from] Computing for function bug_memexec +< [from] Done for function bug_memexec +< [from] Computing for function escaping_formal +< [from] Computing for function escaping_formal <-escaping_formal +< [from] Done for function escaping_formal +< [from] Done for function escaping_formal +< [from] Computing for function escaping_local +< [from] Computing for function escaping_local <-escaping_local +< [from] Done for function escaping_local +< [from] Done for function escaping_local +< [from] Computing for function escaping_stack +< [from] Computing for function escaping_stack <-escaping_stack +< [from] Done for function escaping_stack +< [from] Done for function escaping_stack +< [from] Computing for function even +< [from] Computing for function odd <-even +< [from] Computing for function even <-odd <-even +< [from] Done for function even +< [from] Done for function odd +< [from] Done for function even +< [from] Computing for function even_ptr +< [from] Computing for function odd_ptr <-even_ptr +< [from] Computing for function even_ptr <-odd_ptr <-even_ptr +< [from] Done for function even_ptr +< [from] Done for function odd_ptr +< [from] Done for function even_ptr +< [from] Computing for function factorial +< [from] Computing for function factorial <-factorial +< [from] Done for function factorial +< [from] Done for function factorial +< [from] Computing for function factorial_ptr +< [from] Computing for function factorial_ptr <-factorial_ptr +< [from] Done for function factorial_ptr +< [from] Done for function factorial_ptr +< [from] Computing for function fill_array +< [from] Computing for function fill_array <-fill_array +< [from] Done for function fill_array +< [from] Done for function fill_array +< [from] Computing for function five +< [from] Computing for function five <-five +< [from] Done for function five +< [from] Done for function five +< [from] Computing for function precond +< [from] Computing for function precond <-precond +< [from] Done for function precond +< [from] Done for function precond +< [from] Computing for function sum +< [from] Computing for function sum <-sum +< [from] Done for function sum +< [from] Done for function sum +< [from] Computing for function sum_and_fact +< [from] Computing for function sum_and_fact <-sum_and_fact +< [from] Done for function sum_and_fact +< [from] Done for function sum_and_fact +< [from] Computing for function sum_ptr +< [from] Computing for function sum_ptr <-sum_ptr +< [from] Done for function sum_ptr +< [from] Done for function sum_ptr +< [from] Computing for function syracuse +< [from] Computing for function syracuse <-syracuse +< [from] Done for function syracuse +< [from] Done for function syracuse +< [from] Computing for function syracuse_ptr +< [from] Computing for function syracuse_ptr <-syracuse_ptr +< [from] Done for function syracuse_ptr +< [from] Done for function syracuse_ptr +< [from] Computing for function binary_search +< [from] Computing for function binary_search <-binary_search +< [from] Done for function binary_search +< [from] Done for function binary_search +< [from] Computing for function fibonacci +< [from] Computing for function fibonacci <-fibonacci +< [from] Done for function fibonacci +< [from] Done for function fibonacci +< [from] Computing for function fibonacci_ptr +< [from] Computing for function fibonacci_ptr <-fibonacci_ptr +< [from] Done for function fibonacci_ptr +< [from] Done for function fibonacci_ptr +< [from] Computing for function test_array +< [from] Computing for function Frama_C_interval <-test_array +< [from] Done for function Frama_C_interval +< [from] Done for function test_array +< [from] Computing for function main +< [from] Done for function main +< [from] ====== DEPENDENCIES COMPUTED ====== +< These dependencies hold at termination for the executions that terminate: +< [from] Function Frama_C_interval: +< Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) +< \result FROM Frama_C_entropy_source; min; max +< [from] Function alarm: +< res FROM i +< tmp FROM i +< __retres FROM i +< \result FROM i +< [from] Function decr: +< NO EFFECTS +< [from] Function bug_memexec: +< NO EFFECTS +< [from] Function escaping_formal: +< p FROM count +< x FROM nondet; count (and SELF) +< [from] Function escaping_local: +< p FROM count +< [from] Function escaping_stack: +< p FROM count; q +< a FROM nondet; count; q (and SELF) +< [from] Function even: +< __retres FROM n +< __retres FROM n +< \result FROM n +< [from] Function even_ptr: +< x FROM n; result (and SELF) +< a FROM n (and SELF) +< b FROM n; result (and SELF) +< [from] Function factorial: +< res FROM i +< tmp FROM i +< __retres FROM i +< \result FROM i +< [from] Function factorial_ptr: +< y FROM p_0; result; x +< [from] Function fill_array: +< array{[0]; [10]} FROM data; start; end (and SELF) +< [from] Function five: +< __retres FROM nondet +< \result FROM nondet +< [from] Function odd: +< __retres FROM n +< \result FROM n +< [from] Function odd_ptr: +< y FROM n; result (and SELF) +< a FROM n; result (and SELF) +< [from] Function precond: +< y FROM x +< [from] Function sum: +< res FROM i +< tmp FROM i +< __retres FROM i +< \result FROM i +< [from] Function sum_and_fact: +< x FROM i; sum_0 +< __retres FROM i +< \result FROM i +< [from] Function sum_ptr: +< y FROM p_0; result; x +< [from] Function syracuse: +< __retres FROM i +< \result FROM i +< [from] Function syracuse_ptr: +< y FROM p_0; result; x +< [from] Function binary_search: +< mid FROM start; end +< __retres FROM data; toFind; start; end; array[7] +< \result FROM data; toFind; start; end; array[7] +< [from] Function fibonacci: +< __retres FROM n +< \result FROM n +< [from] Function fibonacci_ptr: +< y FROM p_0; result; x +< [from] Function test_array: +< Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) +< [from] Function main: +< Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) +< p FROM \nothing +< [from] ====== END OF DEPENDENCIES ====== +< [inout] Out (internal) for function alarm: +< res; tmp; __retres +< [inout] Inputs for function alarm: +< i; res; tmp; __retres +< [inout] Out (internal) for function decr: +< x +< [inout] Inputs for function decr: +< nondet; i +< [inout] Out (internal) for function bug_memexec: +< \nothing +< [inout] Inputs for function bug_memexec: +< nondet +< [inout] Out (internal) for function escaping_formal: +< p; x +< [inout] Inputs for function escaping_formal: +< nondet; p; count; x +< [inout] Out (internal) for function escaping_local: +< p; x +< [inout] Inputs for function escaping_local: +< nondet; p; count +< [inout] Out (internal) for function escaping_stack: +< p; x; a +< [inout] Inputs for function escaping_stack: +< nondet; p; count; q +< [inout] Out (internal) for function even: +< tmp; tmp; __retres; __retres +< [inout] Inputs for function even: +< n; tmp; n; tmp; __retres; __retres +< [inout] Out (internal) for function even_ptr: +< x; y; b +< [inout] Inputs for function even_ptr: +< n; result; x; n; result; y +< [inout] Out (internal) for function factorial: +< res; tmp; __retres +< [inout] Inputs for function factorial: +< i; res; tmp; __retres +< [inout] Out (internal) for function factorial_ptr: +< arg; y +< [inout] Inputs for function factorial_ptr: +< p_0; result; res; x +< [inout] Out (internal) for function fill_array: +< array[0..15] +< [inout] Inputs for function fill_array: +< data; start; end +< [inout] Out (internal) for function five: +< tmp; __retres +< [inout] Inputs for function five: +< nondet; tmp; __retres +< [inout] Out (internal) for function odd: +< tmp; tmp; __retres; __retres +< [inout] Inputs for function odd: +< n; tmp; n; tmp; __retres; __retres +< [inout] Out (internal) for function odd_ptr: +< x; y; a +< [inout] Inputs for function odd_ptr: +< n; result; x; n; result; y +< [inout] Out (internal) for function precond: +< ANYTHING(origin:Unknown) +< [inout] Inputs for function precond: +< nondet; x +< [inout] Out (internal) for function sum: +< res; tmp; __retres +< [inout] Inputs for function sum: +< i; res; tmp; __retres +< [inout] Out (internal) for function sum_and_fact: +< fact; tmp_0; x; __retres +< [inout] Inputs for function sum_and_fact: +< i; sum_0; tmp; fact; tmp_0; __retres +< [inout] Out (internal) for function sum_ptr: +< arg; y +< [inout] Inputs for function sum_ptr: +< p_0; result; res; x +< [inout] Out (internal) for function syracuse: +< prev; __retres +< [inout] Inputs for function syracuse: +< n; i; prev; __retres +< [inout] Out (internal) for function syracuse_ptr: +< prev_arg; y +< [inout] Inputs for function syracuse_ptr: +< n; p_0; result; prev_res; x +< [inout] Out (internal) for function binary_search: +< mid; tmp; tmp_0; __retres +< [inout] Inputs for function binary_search: +< data; toFind; start; end; mid; tmp; tmp_0; array[7]; __retres +< [inout] Out (internal) for function fibonacci: +< x; y; __retres +< [inout] Inputs for function fibonacci: +< n; x; y; __retres +< [inout] Out (internal) for function fibonacci_ptr: +< a; y +< [inout] Inputs for function fibonacci_ptr: +< p_0; result; x; y; a; x +< [inout] Out (internal) for function test_array: +< Frama_C_entropy_source; array[0..15]; i; j; end +< [inout] Inputs for function test_array: +< Frama_C_entropy_source; nondet +< [inout] Out (internal) for function main: +< ANYTHING(origin:Unknown) +< [inout] Inputs for function main: +< Frama_C_entropy_source; nondet; p +--- +> [eva] tests/value/recursion.c:18: User Error: +> The binding to APRON domains does not support recursive calls. +> [kernel] Plug-in eva aborted: invalid user input. diff --git a/tests/value/oracle_apron/recursion.1.res.oracle b/tests/value/oracle_apron/recursion.1.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..7556d61ac85a09c7c94d6176127ef66655521b91 --- /dev/null +++ b/tests/value/oracle_apron/recursion.1.res.oracle @@ -0,0 +1,510 @@ +10,514c10,12 +< [eva] tests/value/recursion.c:18: Warning: +< Using specification of function five for recursive calls of depth 20. +< Analysis of function five is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function five +< [eva:alarm] tests/value/recursion.c:15: Warning: +< function five: postcondition got status unknown. +< [eva] tests/value/recursion.c:342: Frama_C_show_each_5: {5} +< [eva:recursion] tests/value/recursion.c:28: +< detected recursive call of function sum. +< [eva] tests/value/recursion.c:344: Frama_C_show_each_91: {91} +< [eva:recursion] tests/value/recursion.c:37: +< detected recursive call of function factorial. +< [eva] tests/value/recursion.c:346: Frama_C_show_each_120: {120} +< [eva:recursion] tests/value/recursion.c:46: +< detected recursive call of function syracuse. +< [eva] tests/value/recursion.c:348: Frama_C_show_each_1: {1} +< [eva:recursion] tests/value/recursion.c:59: +< detected recursive call of function fibonacci. +< [eva:recursion] tests/value/recursion.c:60: +< detected recursive call of function fibonacci. +< [eva] tests/value/recursion.c:350: Frama_C_show_each_89: {89} +< [eva:recursion] tests/value/recursion.c:76: +< detected recursive call of function sum_ptr. +< [eva] tests/value/recursion.c:355: Frama_C_show_each_91: {91} +< [eva:recursion] tests/value/recursion.c:89: +< detected recursive call of function factorial_ptr. +< [eva] tests/value/recursion.c:358: Frama_C_show_each_120: {120} +< [eva:recursion] tests/value/recursion.c:101: +< detected recursive call of function syracuse_ptr. +< [eva] tests/value/recursion.c:361: Frama_C_show_each_1: {1} +< [eva:recursion] tests/value/recursion.c:117: +< detected recursive call of function fibonacci_ptr. +< [eva:recursion] tests/value/recursion.c:119: +< detected recursive call of function fibonacci_ptr. +< [eva] tests/value/recursion.c:364: Frama_C_show_each_89: {89} +< [eva:recursion] tests/value/recursion.c:137: +< detected recursive call of function sum_and_fact. +< [eva] tests/value/recursion.c:368: Frama_C_show_each_36_40320: {36}, {40320} +< [eva:recursion] tests/value/recursion.c:161: +< detected recursive call of function odd. +< [eva:recursion] tests/value/recursion.c:152: +< detected recursive call of function even. +< [eva] tests/value/recursion.c:373: Frama_C_show_each_1: {1}, {1} +< [eva] tests/value/recursion.c:376: Frama_C_show_each_0: {0}, {0} +< [eva:recursion] tests/value/recursion.c:183: +< detected recursive call of function odd_ptr. +< [eva:recursion] tests/value/recursion.c:171: +< detected recursive call of function even_ptr. +< [eva] tests/value/recursion.c:379: Frama_C_show_each_1: {1}, {1} +< [eva] tests/value/recursion.c:382: Frama_C_show_each_0: {0}, {0} +< [eva] using specification for function Frama_C_interval +< [eva:alarm] tests/value/recursion.c:24: Warning: +< function sum: postcondition got status unknown. +< [eva] tests/value/recursion.c:388: Frama_C_show_each_6_66: [6..66] +< [eva:alarm] tests/value/recursion.c:69: Warning: +< function sum_ptr: postcondition got status unknown. +< [eva] tests/value/recursion.c:391: Frama_C_show_each_6_66: [6..66] +< [eva] tests/value/recursion.c:394: Frama_C_show_each_2_89: [2..89] +< [eva] tests/value/recursion.c:397: Frama_C_show_each_2_89: [2..89] +< [eva:alarm] tests/value/recursion.c:222: Warning: +< function fill_array: precondition got status invalid. +< [eva:alarm] tests/value/recursion.c:226: Warning: +< function fill_array: precondition got status unknown. +< [eva:recursion] tests/value/recursion.c:200: +< detected recursive call of function fill_array. +< [eva:alarm] tests/value/recursion.c:200: Warning: +< function fill_array: precondition got status unknown. +< [eva:alarm] tests/value/recursion.c:199: Warning: +< out of bounds write. assert \valid(data + start); +< [kernel] tests/value/recursion.c:199: Warning: +< all target addresses were invalid. This path is assumed to be dead. +< [eva:alarm] tests/value/recursion.c:194: Warning: +< function fill_array: postcondition got status unknown. +< [eva:alarm] tests/value/recursion.c:228: Warning: +< function binary_search: precondition \initialized(data + (start .. end)) got status unknown. +< [eva:recursion] tests/value/recursion.c:214: +< detected recursive call of function binary_search. +< [eva] tests/value/recursion.c:229: Frama_C_show_each_3: {3} +< [eva:recursion] tests/value/recursion.c:216: +< detected recursive call of function binary_search. +< [eva] tests/value/recursion.c:231: Frama_C_show_each_12: {12} +< [eva] tests/value/recursion.c:233: Frama_C_show_each_minus1: {-1} +< [eva] tests/value/recursion.c:238: Frama_C_show_each_7_11: {7; 8; 9; 10; 11} +< [eva] tests/value/recursion.c:241: Frama_C_show_each_minus_1_15: [-1..15] +< [eva:recursion] tests/value/recursion.c:252: +< detected recursive call of function alarm. +< [eva:alarm] tests/value/recursion.c:252: Warning: +< signed overflow. assert i * tmp ≤ 2147483647; +< (tmp from alarm(i - 1)) +< [eva:recursion] tests/value/recursion.c:261: +< detected recursive call of function precond. +< [eva:alarm] tests/value/recursion.c:261: Warning: +< function precond: precondition got status invalid. +< [eva:recursion] tests/value/recursion.c:276: +< detected recursive call of function escaping_local. +< [eva] tests/value/recursion.c:279: Frama_C_show_each_1: {1} +< [eva:locals-escaping] tests/value/recursion.c:277: Warning: +< locals {x} escaping the scope of a block of escaping_local through p +< [eva:alarm] tests/value/recursion.c:278: Warning: +< accessing left-value that contains escaping addresses. +< assert ¬\dangling(&p); +< [kernel] tests/value/recursion.c:278: Warning: +< all target addresses were invalid. This path is assumed to be dead. +< [eva:recursion] tests/value/recursion.c:291: +< detected recursive call of function escaping_formal. +< [eva] tests/value/recursion.c:294: Frama_C_show_each_1: {1} +< [eva:locals-escaping] tests/value/recursion.c:291: Warning: +< locals {x} escaping the scope of escaping_formal through p +< [eva:alarm] tests/value/recursion.c:293: Warning: +< accessing left-value that contains escaping addresses. +< assert ¬\dangling(&p); +< [kernel] tests/value/recursion.c:293: Warning: +< all target addresses were invalid. This path is assumed to be dead. +< [eva:recursion] tests/value/recursion.c:307: +< detected recursive call of function escaping_stack. +< [eva] tests/value/recursion.c:310: Frama_C_show_each_1_2: {1} +< [eva] tests/value/recursion.c:310: Frama_C_show_each_1_2: {2} +< [eva:locals-escaping] tests/value/recursion.c:308: Warning: +< locals {x} escaping the scope of a block of escaping_stack through p +< [eva:alarm] tests/value/recursion.c:309: Warning: +< accessing left-value that contains escaping addresses. +< assert ¬\dangling(&p); +< [kernel] tests/value/recursion.c:309: Warning: +< all target addresses were invalid. This path is assumed to be dead. +< [eva:recursion] tests/value/recursion.c:323: +< detected recursive call of function decr. +< [eva] tests/value/recursion.c:323: Warning: +< Using specification of function decr for recursive calls of depth 20. +< Analysis of function decr is thus incomplete and its soundness +< relies on the written specification. +< [eva] using specification for function decr +< [eva] done for function main +< [eva] ====== VALUES COMPUTED ====== +< [eva:final-states] Values at end of function alarm: +< res ∈ [2..2147483647] +< __retres ∈ [1..2147483647] +< [eva:final-states] Values at end of function decr: +< +< [eva:final-states] Values at end of function bug_memexec: +< +< [eva:final-states] Values at end of function escaping_formal: +< p ∈ {{ &x ; &\copy<x>[5] }} or ESCAPINGADDR +< x ∈ {5; 16} +< [eva:final-states] Values at end of function escaping_local: +< p ∈ {{ &\copy<x>[5] }} or ESCAPINGADDR +< [eva:final-states] Values at end of function escaping_stack: +< p ∈ {{ &\copy<x>[4] }} or ESCAPINGADDR +< [eva:final-states] Values at end of function even: +< __retres ∈ UNINITIALIZED +< __retres ∈ {0; 1} +< [eva:final-states] Values at end of function even_ptr: +< x ∈ {0; 1} +< b ∈ {0; 1} +< [eva:final-states] Values at end of function factorial: +< res ∈ {2; 6; 24; 120} +< __retres ∈ {1; 2; 6; 24; 120} +< [eva:final-states] Values at end of function factorial_ptr: +< y ∈ {91; 120} +< [eva:final-states] Values at end of function fill_array: +< array[0] ∈ {0} +< [1] ∈ {1} +< [2] ∈ {2} +< [3] ∈ {3} +< [4] ∈ {4} +< [5] ∈ {5} +< [6] ∈ {6} +< [7] ∈ {7} +< [8] ∈ {8} +< [9] ∈ {9} +< [10] ∈ {10} +< [11] ∈ {11} or UNINITIALIZED +< [12] ∈ {12} or UNINITIALIZED +< [13] ∈ {13} or UNINITIALIZED +< [14] ∈ {14} or UNINITIALIZED +< [15] ∈ {15} or UNINITIALIZED +< [eva:final-states] Values at end of function five: +< __retres ∈ {5} +< [eva:final-states] Values at end of function odd: +< __retres ∈ {0; 1} +< __retres ∈ UNINITIALIZED +< [eva:final-states] Values at end of function odd_ptr: +< y ∈ {0; 1} +< a ∈ {0; 1} +< [eva:final-states] Values at end of function precond: +< y ∈ [-100..-6] +< [eva:final-states] Values at end of function sum: +< res ∈ [3..91] +< __retres ∈ [1..91] +< [eva:final-states] Values at end of function sum_and_fact: +< x ∈ {11; 36} +< __retres ∈ {1; 2; 6; 24; 120; 720; 5040; 40320} +< [eva:final-states] Values at end of function sum_ptr: +< y ∈ [0..91] +< [eva:final-states] Values at end of function syracuse: +< __retres ∈ [1..16] +< [eva:final-states] Values at end of function syracuse_ptr: +< y ∈ {1; 120} +< [eva:final-states] Values at end of function binary_search: +< mid ∈ [3..16] +< __retres ∈ [-1..15] +< [eva:final-states] Values at end of function fibonacci: +< __retres ∈ [0..89] +< [eva:final-states] Values at end of function fibonacci_ptr: +< y ∈ [0..89] +< [eva:final-states] Values at end of function test_array: +< Frama_C_entropy_source ∈ [--..--] +< array[0] ∈ {0} +< [1] ∈ {1} +< [2] ∈ {2} +< [3] ∈ {3} +< [4] ∈ {4} +< [5] ∈ {5} +< [6] ∈ {6} +< [7] ∈ {7} +< [8] ∈ {8} +< [9] ∈ {9} +< [10] ∈ {10} +< [11] ∈ {11} +< [12] ∈ {12} +< [13] ∈ {13} +< [14] ∈ {14} +< [15] ∈ {15} +< i ∈ [-1..15] +< j ∈ [7..18] +< end ∈ {10; 11; 12; 13; 14; 15} +< [eva:final-states] Values at end of function main: +< Frama_C_entropy_source ∈ [--..--] +< p ∈ ESCAPINGADDR +< a ∈ {0} +< b ∈ {0} +< x ∈ [10..20] +< y ∈ [3628800..2147483647] +< [from] Computing for function alarm +< [from] Computing for function alarm <-alarm +< [from] Done for function alarm +< [from] Done for function alarm +< [from] Computing for function decr +< [from] Computing for function decr <-decr +< [from] Done for function decr +< [from] Done for function decr +< [from] Computing for function bug_memexec +< [from] Done for function bug_memexec +< [from] Computing for function escaping_formal +< [from] Computing for function escaping_formal <-escaping_formal +< [from] Done for function escaping_formal +< [from] Done for function escaping_formal +< [from] Computing for function escaping_local +< [from] Computing for function escaping_local <-escaping_local +< [from] Done for function escaping_local +< [from] Done for function escaping_local +< [from] Computing for function escaping_stack +< [from] Computing for function escaping_stack <-escaping_stack +< [from] Done for function escaping_stack +< [from] Done for function escaping_stack +< [from] Computing for function even +< [from] Computing for function odd <-even +< [from] Computing for function even <-odd <-even +< [from] Done for function even +< [from] Done for function odd +< [from] Done for function even +< [from] Computing for function even_ptr +< [from] Computing for function odd_ptr <-even_ptr +< [from] Computing for function even_ptr <-odd_ptr <-even_ptr +< [from] Done for function even_ptr +< [from] Done for function odd_ptr +< [from] Done for function even_ptr +< [from] Computing for function factorial +< [from] Computing for function factorial <-factorial +< [from] Done for function factorial +< [from] Done for function factorial +< [from] Computing for function factorial_ptr +< [from] Computing for function factorial_ptr <-factorial_ptr +< [from] Done for function factorial_ptr +< [from] Done for function factorial_ptr +< [from] Computing for function fill_array +< [from] Computing for function fill_array <-fill_array +< [from] Done for function fill_array +< [from] Done for function fill_array +< [from] Computing for function five +< [from] Computing for function five <-five +< [from] Done for function five +< [from] Done for function five +< [from] Computing for function precond +< [from] Computing for function precond <-precond +< [from] Done for function precond +< [from] Done for function precond +< [from] Computing for function sum +< [from] Computing for function sum <-sum +< [from] Done for function sum +< [from] Done for function sum +< [from] Computing for function sum_and_fact +< [from] Computing for function sum_and_fact <-sum_and_fact +< [from] Done for function sum_and_fact +< [from] Done for function sum_and_fact +< [from] Computing for function sum_ptr +< [from] Computing for function sum_ptr <-sum_ptr +< [from] Done for function sum_ptr +< [from] Done for function sum_ptr +< [from] Computing for function syracuse +< [from] Computing for function syracuse <-syracuse +< [from] Done for function syracuse +< [from] Done for function syracuse +< [from] Computing for function syracuse_ptr +< [from] Computing for function syracuse_ptr <-syracuse_ptr +< [from] Done for function syracuse_ptr +< [from] Done for function syracuse_ptr +< [from] Computing for function binary_search +< [from] Computing for function binary_search <-binary_search +< [from] Done for function binary_search +< [from] Done for function binary_search +< [from] Computing for function fibonacci +< [from] Computing for function fibonacci <-fibonacci +< [from] Done for function fibonacci +< [from] Done for function fibonacci +< [from] Computing for function fibonacci_ptr +< [from] Computing for function fibonacci_ptr <-fibonacci_ptr +< [from] Done for function fibonacci_ptr +< [from] Done for function fibonacci_ptr +< [from] Computing for function test_array +< [from] Computing for function Frama_C_interval <-test_array +< [from] Done for function Frama_C_interval +< [from] Done for function test_array +< [from] Computing for function main +< [from] Done for function main +< [from] ====== DEPENDENCIES COMPUTED ====== +< These dependencies hold at termination for the executions that terminate: +< [from] Function Frama_C_interval: +< Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) +< \result FROM Frama_C_entropy_source; min; max +< [from] Function alarm: +< res FROM i +< tmp FROM i +< __retres FROM i +< \result FROM i +< [from] Function decr: +< NO EFFECTS +< [from] Function bug_memexec: +< NO EFFECTS +< [from] Function escaping_formal: +< p FROM count (and SELF) +< x FROM nondet; count (and SELF) +< [from] Function escaping_local: +< p FROM count (and SELF) +< [from] Function escaping_stack: +< p FROM count; q (and SELF) +< [from] Function even: +< __retres FROM n (and SELF) +< __retres FROM n +< \result FROM n +< [from] Function even_ptr: +< x FROM n; result (and SELF) +< a FROM n (and SELF) +< b FROM n; result (and SELF) +< [from] Function factorial: +< res FROM i +< tmp FROM i +< __retres FROM i +< \result FROM i +< [from] Function factorial_ptr: +< y FROM p_0; result; x (and SELF) +< [from] Function fill_array: +< array[0..15] FROM data; start; end (and SELF) +< [from] Function five: +< __retres FROM nondet +< \result FROM nondet +< [from] Function odd: +< __retres FROM n +< \result FROM n +< [from] Function odd_ptr: +< y FROM n; result (and SELF) +< a FROM n; result (and SELF) +< [from] Function precond: +< y FROM x +< [from] Function sum: +< res FROM i +< tmp FROM i +< __retres FROM i +< \result FROM i +< [from] Function sum_and_fact: +< x FROM i; sum_0 (and SELF) +< __retres FROM i +< \result FROM i +< [from] Function sum_ptr: +< y FROM p_0; result; x (and SELF) +< [from] Function syracuse: +< __retres FROM n; i +< \result FROM n; i +< [from] Function syracuse_ptr: +< y FROM p_0; result; x (and SELF) +< [from] Function binary_search: +< mid FROM start; end +< __retres FROM data; toFind; start; end; array[3..15] +< \result FROM data; toFind; start; end; array[3..15] +< [from] Function fibonacci: +< __retres FROM n +< \result FROM n +< [from] Function fibonacci_ptr: +< y FROM p_0; result; x (and SELF) +< [from] Function test_array: +< Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) +< [from] Function main: +< Frama_C_entropy_source FROM Frama_C_entropy_source (and SELF) +< p FROM \nothing (and SELF) +< [from] ====== END OF DEPENDENCIES ====== +< [inout] Out (internal) for function alarm: +< res; tmp; __retres +< [inout] Inputs for function alarm: +< i; res; tmp; __retres +< [inout] Out (internal) for function decr: +< x +< [inout] Inputs for function decr: +< nondet; i +< [inout] Out (internal) for function bug_memexec: +< \nothing +< [inout] Inputs for function bug_memexec: +< nondet +< [inout] Out (internal) for function escaping_formal: +< p; x +< [inout] Inputs for function escaping_formal: +< nondet; p; count; x +< [inout] Out (internal) for function escaping_local: +< p; x +< [inout] Inputs for function escaping_local: +< nondet; p; count +< [inout] Out (internal) for function escaping_stack: +< p; x +< [inout] Inputs for function escaping_stack: +< nondet; p; count; q +< [inout] Out (internal) for function even: +< tmp; tmp; __retres; __retres +< [inout] Inputs for function even: +< n; tmp; n; tmp; __retres; __retres +< [inout] Out (internal) for function even_ptr: +< x; y; b +< [inout] Inputs for function even_ptr: +< n; result; x; n; result; y +< [inout] Out (internal) for function factorial: +< res; tmp; __retres +< [inout] Inputs for function factorial: +< i; res; tmp; __retres +< [inout] Out (internal) for function factorial_ptr: +< arg; y +< [inout] Inputs for function factorial_ptr: +< p_0; result; res; x +< [inout] Out (internal) for function fill_array: +< array[0..15] +< [inout] Inputs for function fill_array: +< data; start; end +< [inout] Out (internal) for function five: +< tmp; __retres +< [inout] Inputs for function five: +< nondet; tmp; __retres +< [inout] Out (internal) for function odd: +< tmp; tmp; __retres; __retres +< [inout] Inputs for function odd: +< n; tmp; n; tmp; __retres; __retres +< [inout] Out (internal) for function odd_ptr: +< x; y; a +< [inout] Inputs for function odd_ptr: +< n; result; x; n; result; y +< [inout] Out (internal) for function precond: +< y +< [inout] Inputs for function precond: +< nondet; x +< [inout] Out (internal) for function sum: +< res; tmp; __retres +< [inout] Inputs for function sum: +< i; res; tmp; __retres +< [inout] Out (internal) for function sum_and_fact: +< fact; tmp_0; x; __retres +< [inout] Inputs for function sum_and_fact: +< i; sum_0; tmp; fact; tmp_0; __retres +< [inout] Out (internal) for function sum_ptr: +< arg; y +< [inout] Inputs for function sum_ptr: +< p_0; result; res; x +< [inout] Out (internal) for function syracuse: +< prev; __retres +< [inout] Inputs for function syracuse: +< n; i; prev; __retres +< [inout] Out (internal) for function syracuse_ptr: +< prev_arg; y +< [inout] Inputs for function syracuse_ptr: +< n; p_0; result; prev_res; x +< [inout] Out (internal) for function binary_search: +< mid; tmp; tmp_0; __retres +< [inout] Inputs for function binary_search: +< data; toFind; start; end; mid; tmp; tmp_0; array[3..15]; __retres +< [inout] Out (internal) for function fibonacci: +< x; y; __retres +< [inout] Inputs for function fibonacci: +< n; x; y; __retres +< [inout] Out (internal) for function fibonacci_ptr: +< a; y +< [inout] Inputs for function fibonacci_ptr: +< p_0; result; x; y; a; x +< [inout] Out (internal) for function test_array: +< Frama_C_entropy_source; array[0..15]; i; j; end +< [inout] Inputs for function test_array: +< Frama_C_entropy_source; nondet +< [inout] Out (internal) for function main: +< Frama_C_entropy_source; p; a; b; x; y; tmp; tmp_0; tmp_1; tmp_2 +< [inout] Inputs for function main: +< Frama_C_entropy_source; nondet; p +--- +> [eva] tests/value/recursion.c:18: User Error: +> The binding to APRON domains does not support recursive calls. +> [kernel] Plug-in eva aborted: invalid user input. diff --git a/tests/value/oracle_apron/recursion.2.res.oracle b/tests/value/oracle_apron/recursion.2.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..61f9a6838a929c95b6fd56661df773f25660b4e3 --- /dev/null +++ b/tests/value/oracle_apron/recursion.2.res.oracle @@ -0,0 +1,10 @@ +10,12d9 +< [eva] tests/value/recursion.c:429: Frama_C_show_each_10: {10} +< [eva] tests/value/recursion.c:434: Frama_C_show_each_36: {36} +< [eva] using specification for function Frama_C_interval +14,16c11 +< Recursive call to sum_nospec without a specification. Try to increase +< the -eva-unroll-recursive-calls parameter or write a specification +< for function sum_nospec. +--- +> The binding to APRON domains does not support recursive calls. diff --git a/tests/value/rec.i b/tests/value/rec.i deleted file mode 100644 index dcbe796370f429c7945141198bde9e110c758103..0000000000000000000000000000000000000000 --- a/tests/value/rec.i +++ /dev/null @@ -1,5 +0,0 @@ -void main() { - int X=0; - if (X) main(); - -} diff --git a/tests/value/recursion.c b/tests/value/recursion.c new file mode 100644 index 0000000000000000000000000000000000000000..1dad1842fcd65526388f6ca3bc2d1a08a340c7d3 --- /dev/null +++ b/tests/value/recursion.c @@ -0,0 +1,439 @@ +/* run.config* + STDOPT: +"-eva-no-show-progress -eva-unroll-recursive-calls 0" + STDOPT: +"-eva-no-show-progress -eva-unroll-recursive-calls 20" + EXIT: 1 + STDOPT: +"-eva-no-show-progress -eva-unroll-recursive-calls 5 -main main_fail" +*/ + +#include <__fc_builtin.h> + +volatile int nondet; + +/* ----- Simple recursive functions. ---------------------------------------- */ + +/*@ assigns \result \from \nothing; + ensures \result == 5; */ +int five () { + if (nondet) + return five(); + else + return 5; +} + +/*@ assigns \result \from i; + ensures \result == (i * (i+1)) / 2; */ +unsigned int sum (unsigned int i) { + if (i < 2) + return i; + unsigned int res = i + sum(i - 1); + return res; +} + +/*@ assigns \result \from i; */ +unsigned int factorial (unsigned int i) { + if(i <= 1) { + return 1; + } + unsigned int res = i * factorial(i - 1); + return res; +} + +/*@ assigns \result \from i, n; */ +unsigned int syracuse (unsigned int n, unsigned int i) { + if (i == 0) + return n; + else { + unsigned int prev = syracuse(n, i-1); + if (prev % 2) + return 3*prev + 1; + else + return prev / 2; + } +} + +/*@ assigns \result \from n; */ +unsigned int fibonacci (unsigned int n) { + if (n < 2) + return n; + else { + unsigned int x = fibonacci(n-1); + unsigned int y = fibonacci(n-2); + return x + y; + } +} + +/* ----- Recursive functions using pointers on the stack. ------------------ */ + +/*@ assigns *result \from *p; + ensures \initialized(result); + ensures *result == (*p * (*p+1)) / 2; */ +void sum_ptr (unsigned int *p, unsigned int *result) { + if (*p < 2) + *result = *p; + else { + unsigned int res; + unsigned int arg = *p - 1; + sum_ptr(&arg, &res); + *result = *p + res; + } +} + +/*@ assigns *result \from *p; */ +void factorial_ptr(unsigned int *p, unsigned int *result) { + if(*p < 2) { + *result = 1; + } + else { + unsigned int res; + unsigned int arg = *p - 1; + factorial_ptr(&arg, &res); + *result = *p * res; + } +} + +/*@ assigns *result \from n, *p; */ +void syracuse_ptr (unsigned int n, unsigned int *p, unsigned int *result) { + if (*p == 0) + *result = n; + else { + unsigned int prev_res; + unsigned int prev_arg = *p - 1; + syracuse_ptr(n, &prev_arg, &prev_res); + if (prev_res % 2) + *result = 3*prev_res + 1; + else + *result = prev_res / 2; + } +} + +/*@ assigns *result \from *p; */ +void fibonacci_ptr (unsigned int *p, unsigned int *result) { + if (*p < 2) + *result = *p; + else { + unsigned int x, y; + unsigned int a = *p; + a--; + fibonacci_ptr(&a, &x); + a--; + fibonacci_ptr(&a, &y); + *result = x + y; + } +} + +/* ----- Recursive functions performing several computations at once. ------- */ + +/*@ assigns \result \from i; + assigns *sum \from i; + ensures \initialized(sum); + ensures *sum == (i * (i+1)) / 2; */ +unsigned int sum_and_fact (unsigned int i, unsigned int *sum) { + if (i < 2) { + *sum = i; + return i; + } + else { + unsigned int tmp; + unsigned int fact = i * sum_and_fact(i-1, &tmp); + *sum = i + tmp; + return fact; + } +} + +/* ----- Mutually recursive functions. -------------------------------------- */ + +int even (unsigned int); +void even_ptr (unsigned int, int*); + +/*@ assigns \result \from n; + ensures \result == n % 2; */ +int odd (unsigned int n) { + if (n) + return even(n-1); + else + return 0; +} + +/*@ assigns \result \from n; + ensures \result == !(n % 2); */ +int even (unsigned int n) { + if (n) + return odd(n-1); + else + return 1; +} + +/*@ assigns *result \from n; + ensures *result == n % 2; */ +void odd_ptr (unsigned int n, int *result) { + if (n) { + int x; + even_ptr(n-1, &x); + *result = x; + } + else + *result = 0; +} + +/*@ assigns *result \from n; + ensures *result == !(n % 2); */ +void even_ptr (unsigned int n, int *result) { + if (n) { + int y; + odd_ptr(n-1, &y); + *result = y; + } + else + *result = 1; +} + +/* ----- Recursive functions on arrays. ------------------------------------- */ + +/*@ requires \valid(&data[start..end]); + assigns data[start..end] \from start; + ensures \initialized(&data[start..end]); */ +void fill_array (int *data, int start, int end) { + if (start < 0 || start > end) + return; + else { + data[start] = start; + fill_array(data, start + 1, end); + } +} + +/*@ requires \valid_read(&data[start..end]); + requires \initialized(&data[start..end]); + assigns \result \from data[start..end], toFind; */ +int binary_search (int *data, int toFind, int start, int end) { + int mid = start + (end - start)/2; + if (start > end) + return -1; + else if (data[mid] == toFind) + return mid; + else if (data[mid] > toFind) + return binary_search(data, toFind, start, mid-1); + else + return binary_search(data, toFind, mid+1, end); +} + +void test_array () { + int array[16], i, j, end; + if (nondet) { + fill_array(array, 0, 16); + Frama_C_show_each_unreachable(array); + } + end = Frama_C_interval(10, 16); + fill_array(array, 0, end); + + i = binary_search(array, 3, 0, 15); + Frama_C_show_each_3(i); + i = binary_search(array, 12, 0, 15); + Frama_C_show_each_12(i); + i = binary_search(array, 20, 0, 15); + Frama_C_show_each_minus1(i); + + fill_array(array, 10, 15); + j = Frama_C_interval(7, 11); + i = binary_search(array, j, 0, 15); + Frama_C_show_each_7_11(i); + j = Frama_C_interval(7, 18); + i = binary_search(array, j, 0, 15); + Frama_C_show_each_minus_1_15(i); +} + +/* ----- Alarms or invalid preconditions in recursive calls. ---------------- */ + +/*@ assigns \result \from i; + ensures \result > 0; */ +int alarm (int i) { + if(i <= 1) { + return 1; + } + int res = i * alarm(i - 1); // alarm if enough recursive calls are made. + return res; +} + +/* The precondition should become invalid if enough recursive calls are made. */ +/*@ requires x != 16; */ +void precond (int x) { + int y = 100 / (x - 16); + if (nondet) + precond(x+1); +} + +/* ----- Variables escaping scope through recursive function. --------------- */ + +int *p; + +/*@ assigns p \from \nothing; + assigns *p \from \nothing; */ +void escaping_local (int count) { + if (count <= 0) + return; + else { + int x; + p = &x; + escaping_local(count - 1); + if (nondet) { + *p = 17; // invalid, except the penultimate recursive call where count = 1 + Frama_C_show_each_1(count); + } + } +} + +/*@ assigns p \from \nothing; + assigns *p \from \nothing; */ +void escaping_formal (int count, int x) { + if (count <= 0) + return; + else { + p = &x; + escaping_formal(count - 1, x); + if (nondet) { + *p = 16; // invalid, except the penultimate recursive call where count = 1 + Frama_C_show_each_1(count); + } + } +} + +/*@ assigns p \from q; + assigns *p \from \nothing; */ +void escaping_stack (int count, int *q) { + if (count <= 0) + return; + else { + int x; + p = q; + escaping_stack(count - 1, &x); + if (nondet) { + *p = 15; + Frama_C_show_each_1_2(count); + } + } +} + +/* ----- Bug with memexec. -------------------------------------------------- */ + +/*@ assigns \nothing; */ +void decr (int i) { + if (nondet) + return; + else { + int x = 100 / i; // alarm if i = 0. + decr(i-1); + } +} + +void bug_memexec () { + decr(25); + /* Should trigger the alarm with -eva-unroll-recursive-calls 20, except that + the memexec cache use the results of the previous call to not reinterpret + the call. */ + decr(15); +} + +/* ----- Main. -------------------------------------------------------------- */ + +void main () { + int a, b; + unsigned int x, y; + /* Simple recursive functions. */ + a = five(); + Frama_C_show_each_5(a); + y = sum(13); + Frama_C_show_each_91(y); + y = factorial(5); + Frama_C_show_each_120(y); + y = syracuse(12, 9); + Frama_C_show_each_1(y); + y = fibonacci(11); + Frama_C_show_each_89(y); + + /* Recursive functions using pointers on the stack. */ + x = 13; + sum_ptr(&x, &y); + Frama_C_show_each_91(y); + x = 5; + factorial_ptr(&x, &y); + Frama_C_show_each_120(y); + x = 9; + syracuse_ptr(12, &x, &y); + Frama_C_show_each_1(y); + x = 11; + fibonacci_ptr(&x, &y); + Frama_C_show_each_89(y); + + /* Recursive functions performing several computations at once. */ + y = sum_and_fact(8, &x); + Frama_C_show_each_36_40320(x, y); + + /* Mutually recursive functions. */ + a = odd(7); + b = even(8); + Frama_C_show_each_1(a, b); + a = odd(8); + b = even(9); + Frama_C_show_each_0(a, b); + odd_ptr(7, &a); + even_ptr(8, &b); + Frama_C_show_each_1(a, b); + odd_ptr(8, &a); + even_ptr(9, &b); + Frama_C_show_each_0(a, b); + + /* Using intervals. */ + + x = Frama_C_interval(3, 11); + y = sum(x); + Frama_C_show_each_6_66(y); + y = 0; + sum_ptr(&x, &y); + Frama_C_show_each_6_66(y); + y = 0; + y = fibonacci(x); + Frama_C_show_each_2_89(y); + y = 0; + fibonacci_ptr(&x, &y); + Frama_C_show_each_2_89(y); + + /* Misc */ + test_array(); + + x = Frama_C_interval(10, 20); + y = alarm(x); + if (nondet) { + y = alarm(20); + Frama_C_show_each_unreachable(y); + } + precond(1); + + escaping_local(5); + escaping_formal(5, 5); + escaping_stack(5, &a); + + bug_memexec(); +} + +/* ----- Recursive function without specification. -------------------------- */ + +unsigned int sum_nospec (unsigned int i) { + if (i < 2) + return i; + unsigned int res = i + sum_nospec(i - 1); + return res; +} + +void main_fail () { + int x, y; + y = sum_nospec(4); + Frama_C_show_each_10(y); + /* This call don't fail, as only 4 unrolling of [sum_nospec] are needed before + using the results from the first call stored in the memexec cache. However, + this call would fail without the first call to [sum_no_spec]. */ + y = sum_nospec(8); + Frama_C_show_each_36(y); + x = Frama_C_interval(4, 16); + /* This call cannot be interpreted without a specification for [sum_nospec]. */ + y = sum_nospec(x); + Frama_C_show_each_unreachable(y); +} diff --git a/tests/value/recursion.i b/tests/value/recursion.i deleted file mode 100644 index c3670163290ec5e0d912bff2106bc72a63fc1466..0000000000000000000000000000000000000000 --- a/tests/value/recursion.i +++ /dev/null @@ -1,78 +0,0 @@ -/* run.config* - EXIT: 1 - OPT: -no-autoload-plugins -load-module from,inout,eva -lib-entry -main main -eva @EVA_CONFIG@ -journal-disable - OPT: -no-autoload-plugins -load-module from,inout,eva -lib-entry -main main -eva @EVA_CONFIG@ -eva-ignore-recursive-calls -journal-disable - */ -int G; - -int ff() { - if (G) ff(); - return 5; -} - -int x; - -volatile int c; - -struct s { - int f1; - int f2; -} s; - -// Use given assigns -/*@ assigns x \from x, y; - assigns s.f1 \from s.f2; - assigns \result \from s; -*/ -struct s f(int y) { - x = 2+y; - Frama_C_show_each(x, y); - if (c) { - s = f(y); - Frama_C_show_each(x, y); - } - s.f1 = s.f2; - return s; -} - -// Infers assigns \nothing -void g() { - g(); -} - -// Infer assigns clause that overwrite *p1 and *p2. Currently unsound -void h(int *p1, int *p2) { - h(p1, p2); -} - - -int *pg; - -/* &i escapes. The precondition is true on all calls, but could be computed - false if one overwrites the value of i naively at each call. Currently unsound */ -/*@ requires stage > 0 ==> *pg == i-5; - assigns *pg \from \nothing; - ensures stage > 0 ==> *pg == 8; -*/ -void escaping_formal(int stage, int i) { - pg = &i; - Frama_C_show_each (pg, *pg, stage, i); - escaping_formal (1, i+5); - if (stage > 0) - *pg = 8; - Frama_C_show_each (pg, *pg, stage, i); - pg = 0; -} - -int main() { - G = ff(); - g(); - int v1, v2; - h(&v1, &v2); - Frama_C_show_each(v1, v2); - escaping_formal(0, 10); - struct s r = f(0); - Frama_C_show_each(x); - return r.f1+1; -} - diff --git a/tests/value/recursion2.i b/tests/value/recursion2.i deleted file mode 100644 index ec3ea022c9c7e35712cf0f8b466c78c91b7ceace..0000000000000000000000000000000000000000 --- a/tests/value/recursion2.i +++ /dev/null @@ -1,23 +0,0 @@ -/*run.config* - OPT: -no-autoload-plugins -load-module from,inout,eva -eva @EVA_CONFIG@ -journal-disable -then -input -out -inout - */ -int x, y; - -void h2 (int); -void h1 (int); - -void h1 (int i) { - int r = x; - if (i) - h2 (i); -} -void h2 (int j) { - int q = y; - if (!j) - h1 (j); -} - -void main() { - h2(0); - h1(1); -}