diff --git a/src/plugins/wp/MemLoader.ml b/src/plugins/wp/MemLoader.ml index 4b8f5ba39f7d4b123a16d776839ab9515c977d7c..3c05f23b3bcd838d24e3b3c509b669c980461fa2 100644 --- a/src/plugins/wp/MemLoader.ml +++ b/src/plugins/wp/MemLoader.ml @@ -386,22 +386,20 @@ struct (* --- Initialized --- *) (* -------------------------------------------------------------------------- *) - let rec on_initialized_terms map on_leave obj terms = + let rec initialized_term obj term = match obj with - | C_int _ | C_float _ | C_pointer _ -> on_leave terms + | C_int _ | C_float _ | C_pointer _ -> p_bool term | C_comp ci -> let initialized_field f = - on_initialized_terms map on_leave + initialized_term (object_of f.ftype) - (map (fun t -> e_getfield t (Cfield (f, KInit))) terms) + (e_getfield term (Cfield (f, KInit))) in p_conj (List.map initialized_field ci.cfields) | C_array ai -> let obj_e, ds = Matrix.of_array ai in let denv = Matrix.denv ds in - let values = - map (fun t -> List.fold_left e_get t denv.index_val) terms - in + let values = List.fold_left e_get term denv.index_val in let make_subst var value p = match value with | None -> p @@ -412,15 +410,7 @@ struct List.fold_left (fun p f -> f p) (p_conj denv.index_range) substs in p_forall denv.index_var - (p_imply conj (on_initialized_terms map on_leave obj_e values)) - - let initialized_term = - on_initialized_terms Extlib.id p_bool - - let initialized_monotonic = - on_initialized_terms - (fun f (a, b) -> f a, f b) - (fun (a, b) -> p_imply (p_bool a) (p_bool b)) + (p_imply conj (initialized_term obj_e values)) let initialized_loc sigma obj loc = initialized_term obj (initvalue sigma obj loc) @@ -438,9 +428,137 @@ struct "Invalid infinite range @[<hov 2>+@,(%a@,..%a)@]" Vset.pp_bound low Vset.pp_bound up - let initialized_loc_monotonic seq obj loc = - initialized_monotonic - obj ((initvalue seq.pre obj loc), (initvalue seq.post obj loc)) + (* -------------------------------------------------------------------------- *) + (* --- Initialized Motononicity --- *) + (* -------------------------------------------------------------------------- *) + + let monotonic_init_rec = ref (fun _ _ _ _ -> assert false) + + module MONOTONIC_INIT_COMP = WpContext.Generator(COMP_KEY) + (struct + let name = M.name ^ ".MONOTONIC_INIT_COMP" + type key = int * compinfo + type data = lfun * chunk list * chunk list + + let generate (r,c) = + let x = Lang.freshvar ~basename:"p" (Lang.t_addr()) in + let v = e_var x in + let obj = C_comp c in + let loc = M.of_region_pointer r obj v in (* t_pointer -> loc *) + let domain = M.init_footprint obj loc in + let name = + Format.asprintf "Motononic_%a_%s" pp_rid r (Lang.comp_init_id c) + in + let lfun = Lang.generated_p name in + let xs1,chunks1,sigma1 = signature domain in + let xs2,chunks2,sigma2 = signature domain in + let def = + p_conj + (List.map + (fun f -> + !monotonic_init_rec + sigma1 sigma2 (object_of f.ftype) (M.field loc f) + ) c.cfields) + in + let dfun = Definitions.Predicate( Def , def ) in + Definitions.define_symbol { + d_lfun = lfun ; d_types = 0 ; + d_params = x :: xs1 @ xs2 ; + d_definition = dfun ; + d_cluster = cluster () ; + } ; + (* frame_lemmas lfun obj loc [v] chunks ; *) + lfun, chunks1, chunks2 + + let compile = Lang.local generate + end) + + module MONOTONIC_INIT_ARRAY = WpContext.Generator(ARRAY_KEY) + (struct + let name = M.name ^ ".MONOTONIC_INIT_ARRAY" + type key = int * arrayinfo * Matrix.matrix + type data = lfun * chunk list * chunk list + + let generate (r,ainfo,(obj_e,ds)) = + let x = Lang.freshvar ~basename:"p" (Lang.t_addr()) in + let v = e_var x in + let obj_a = C_array ainfo in + let loc = M.of_region_pointer r obj_a v in (* t_pointer -> loc *) + let domain = M.init_footprint obj_a loc in + let name = + Format.asprintf "Motononic_ArrayInit%a%s_%s" + pp_rid r (Matrix.id ds) (Matrix.natural_id obj_e) + in + let lfun = Lang.generated_p name in + let xs1,chunks1,sigma1 = signature domain in + let xs2,chunks2,sigma2 = signature domain in + let compute_range (bs, ks, es, rs) d = + let b = Lang.freshvar ~basename:"b" Qed.Logic.Int in + let k = Lang.freshvar ~basename:"k" Qed.Logic.Int in + let e = Lang.freshvar ~basename:"e" Qed.Logic.Int in + let bt = e_var b in + let kt = e_var k in + let et = e_var e in + let range = match d with + | None -> p_and (p_leq bt kt) (p_leq kt et) + | Some v -> + p_conj + [p_leq e_zero bt ; p_leq bt kt ; + p_leq kt et ; p_lt et (e_int v)] + in + b :: bs, k :: ks, e :: es, range :: rs + in + (* Note: all in reverse order *) + let bs, ks, es, rs = + List.fold_left compute_range ([], [], [], []) ds + in + let values = + List.fold_left (fun loc k -> M.shift loc obj_e (e_var k)) loc ks + in + let conj = p_conj (List.rev rs) in + let def = p_forall (List.rev ks) + (p_imply conj (!monotonic_init_rec sigma1 sigma2 obj_e values)) + in + let flat_combine l b e = b :: e :: l in + let params = List.fold_left2 flat_combine [] bs es in + Definitions.define_symbol { + d_lfun = lfun ; d_types = 0 ; + d_params = x :: params @ xs1 @ xs2 ; + d_definition = Predicate( Def, def) ; + d_cluster = cluster () ; + } ; + lfun, chunks1, chunks2 + + let compile = Lang.local generate + end) + + let monotonic_init_comp s1 s2 comp loc = + let r, p = M.to_region_pointer loc in + let f, m1, m2 = MONOTONIC_INIT_COMP.get (r, comp) in + p_bool (F.e_fun f (p :: memories s1 m1 @ memories s2 m2)) + + let monotonic_init_array s1 s2 a loc = + let d = Matrix.of_array a in + let r, p = M.to_region_pointer loc in + let f, m1, m2 = MONOTONIC_INIT_ARRAY.get (r,a,d) in + let range size = [ e_zero ; e_add size e_minus_one ] in + let rs = List.(flatten (map range (Matrix.size d))) in + let args = p :: rs @ memories s1 m1 @ memories s2 m2 in + p_bool (F.e_fun f args) + + let initialized_loc_monotonic s1 s2 obj loc = + match obj with + | C_int _ | C_float _ | C_pointer _ -> + p_imply + (p_bool (initvalue s1 obj loc)) + (p_bool (initvalue s2 obj loc)) + | C_comp ci -> monotonic_init_comp s1 s2 ci loc + | C_array ai -> monotonic_init_array s1 s2 ai loc + + let () = monotonic_init_rec := initialized_loc_monotonic + + let initialized_loc_monotonic seq = + initialized_loc_monotonic seq.pre seq.post let initialized_range_monotonic s obj loc a b = let i = Lang.freshvar ~basename:"i" Lang.t_int in @@ -517,7 +635,6 @@ struct havoc seq obj loc let assigned_range s obj l a b = - initialized_range_monotonic s obj l a b :: havoc_length s obj (M.shift l obj a) (e_range a b) let assigned seq obj = function @@ -539,10 +656,12 @@ struct in Assert mono :: !ps | Sarray(loc,obj,n) -> + initialized_range_monotonic seq obj loc e_zero (e_int (n-1)) :: assigned_range seq obj loc e_zero (e_int (n-1)) | Srange(loc,obj,u,v) -> let a = match u with Some a -> a | None -> e_zero in let b = match v with Some b -> b | None -> M.last seq.pre obj loc in + initialized_range_monotonic seq obj loc a b :: assigned_range seq obj loc a b (* -------------------------------------------------------------------------- *) diff --git a/src/plugins/wp/tests/wp_acsl/oracle/assigned_initialized_memtyped.res.oracle b/src/plugins/wp/tests/wp_acsl/oracle/assigned_initialized_memtyped.res.oracle index 9010d65214fc0afad229dbba9b5a89bb9b515245..d9d2221b18fa6c9ebe8759e64856e0c01af26246 100644 --- a/src/plugins/wp/tests/wp_acsl/oracle/assigned_initialized_memtyped.res.oracle +++ b/src/plugins/wp/tests/wp_acsl/oracle/assigned_initialized_memtyped.res.oracle @@ -65,17 +65,15 @@ Goal Check 'CHECK' (file tests/wp_acsl/assigned_initialized_memtyped.i, line 118 Let m = Init_0[shiftfield_F1_S_i(s) <- true]. Let a = shiftfield_F1_S_a(s). Let a_1 = havoc(Init_undef_1, m, shift_sint32(a, 0), 10). -Let a_2 = Load_Init_S1_S(s, a_1). -Let a_3 = Load_Init_S1_S(s, havoc(Init_undef_0, m, s, 11)). -Let P = a_3.Init_F1_S_i. -Let a_4 = a_3.Init_F1_S_a. +Let a_2 = havoc(Init_undef_0, m, s, 11). +Let a_3 = Load_Init_S1_S(s, a_2). Assume { Type: is_sint32(i) /\ is_sint32(i_1). (* Heap *) Type: region(s.base) <= 0. (* Loop assigns ... *) - Have: forall i_2 : Z. let a_5 = shift_sint32(a, i_2) in ((0 <= i_2) -> - ((i_2 <= 9) -> ((m[a_5]=true) -> (a_1[a_5]=true)))). + Have: forall i_2 : Z. let a_4 = shift_sint32(a, i_2) in ((0 <= i_2) -> + ((i_2 <= 9) -> ((m[a_4]=true) -> (a_1[a_4]=true)))). (* Invariant *) Have: (0 <= i) /\ (i <= 10) /\ (forall i_2 : Z. ((0 <= i_2) -> ((i_2 < i) -> @@ -83,16 +81,15 @@ Assume { (* Else *) Have: 10 <= i. (* Loop assigns 'CHECK' *) - Have: ((((a_2.Init_F1_S_i)=true) -> (P=true))) /\ - (forall i_2 : Z. ((0 <= i_2) -> ((i_2 <= 9) -> - (((a_2.Init_F1_S_a)[i_2]=true) -> (a_4[i_2]=true))))). + Have: Motononic__Init_S1_S(s, a_1, a_2). (* Invariant *) Have: (0 <= i_1) /\ (i_1 <= 10). (* Else *) Have: 10 <= i_1. } -Prove: (P=true) /\ - (forall i_2 : Z. ((0 <= i_2) -> ((i_2 <= 9) -> (a_4[i_2]=true)))). +Prove: ((a_3.Init_F1_S_i)=true) /\ + (forall i_2 : Z. ((0 <= i_2) -> ((i_2 <= 9) -> + ((a_3.Init_F1_S_a)[i_2]=true)))). ------------------------------------------------------------ @@ -112,8 +109,6 @@ Effect at line 115 Let m = Init_0[shiftfield_F1_S_i(s) <- true]. Let a = shiftfield_F1_S_a(s). Let a_1 = havoc(Init_undef_0, m, shift_sint32(a, 0), 10). -Let a_2 = Load_Init_S1_S(s, a_1). -Let a_3 = Load_Init_S1_S(s, havoc(Init_undef_1, m, s, 11)). Assume { Type: is_sint32(i_1) /\ is_sint32(i). (* Heap *) @@ -121,8 +116,8 @@ Assume { (* Goal *) When: !invalid(Malloc_0, shift_sint32(a, i), 1). (* Loop assigns ... *) - Have: forall i_2 : Z. let a_4 = shift_sint32(a, i_2) in ((0 <= i_2) -> - ((i_2 <= 9) -> ((m[a_4]=true) -> (a_1[a_4]=true)))). + Have: forall i_2 : Z. let a_2 = shift_sint32(a, i_2) in ((0 <= i_2) -> + ((i_2 <= 9) -> ((m[a_2]=true) -> (a_1[a_2]=true)))). (* Invariant *) Have: (0 <= i_1) /\ (i_1 <= 10) /\ (forall i_2 : Z. ((0 <= i_2) -> ((i_2 < i_1) -> @@ -130,9 +125,7 @@ Assume { (* Else *) Have: 10 <= i_1. (* Loop assigns 'CHECK' *) - Have: ((((a_2.Init_F1_S_i)=true) -> ((a_3.Init_F1_S_i)=true))) /\ - (forall i_2 : Z. ((0 <= i_2) -> ((i_2 <= 9) -> - (((a_2.Init_F1_S_a)[i_2]=true) -> ((a_3.Init_F1_S_a)[i_2]=true))))). + Have: Motononic__Init_S1_S(s, a_1, havoc(Init_undef_1, m, s, 11)). (* Invariant *) Have: (0 <= i) /\ (i <= 10). (* Then *)