diff --git a/src/plugins/wp/cfgWP.ml b/src/plugins/wp/cfgWP.ml index 0a837cbf7378b488a8eb1bea384c7b4b93c72326..cffc2b552ff4bd455dfd384d366a042954c8c13a 100644 --- a/src/plugins/wp/cfgWP.ml +++ b/src/plugins/wp/cfgWP.ml @@ -90,7 +90,7 @@ struct (* Authorized written region from an assigns specification *) type effect = { e_pid : P.t ; (* Assign Property *) - e_kind : a_kind ; (* Requires post effects (in case of loop-assigns) *) + e_post : bool ; (* Requires post effects (loop-assigns or post-assigns) *) e_label : c_label ; (* scope for collection *) e_valid : L.sigma ; (* sigma where locations are filtered for validity *) e_region : L.region ; (* expected from spec *) @@ -444,21 +444,23 @@ struct ainfo.a_assigns in match authorized_region with | None -> None - | Some region -> Some { - e_pid = pid ; - e_kind = ainfo.a_kind ; - e_label = from ; - e_valid = sigma ; - e_region = region ; - e_warn = Warning.Set.empty ; - } + | Some region -> + let post = match ainfo.a_kind with + | LoopAssigns -> true + | StmtAssigns -> NormAtLabels.has_postassigns ainfo.a_assigns + in Some { + e_pid = pid ; + e_post = post ; + e_label = from ; + e_valid = sigma ; + e_region = region ; + e_warn = Warning.Set.empty ; + } let cc_posteffect e vcs = - match e.e_kind with - | StmtAssigns -> vcs - | LoopAssigns -> - let vc = { empty_vc with vars = L.vars e.e_region } in - Gmap.add (Gposteffect e.e_pid) (Splitter.singleton vc) vcs + if not e.e_post then vcs else + let vc = { empty_vc with vars = L.vars e.e_region } in + Gmap.add (Gposteffect e.e_pid) (Splitter.singleton vc) vcs (* -------------------------------------------------------------------------- *) (* --- WP RULES : adding axioms, hypotheses and goals --- *) @@ -549,14 +551,13 @@ struct vars = xs } in let group = - match e.e_kind with - | StmtAssigns -> - Splitter.singleton (setup empty_vc) - | LoopAssigns -> - try Splitter.map setup (Gmap.find (Gposteffect e.e_pid) vcs) - with Not_found -> - Wp_parameters.fatal "Missing post-effect for %a" - WpPropId.pretty e.e_pid + if not e.e_post then + Splitter.singleton (setup empty_vc) + else + try Splitter.map setup (Gmap.find (Gposteffect e.e_pid) vcs) + with Not_found -> + Wp_parameters.fatal "Missing post-effect for %a" + WpPropId.pretty e.e_pid in let target = match sloc with | None -> Gprop e.e_pid diff --git a/src/plugins/wp/clabels.ml b/src/plugins/wp/clabels.ml index c9f7ecf037f95fc9b6ef920628cf923778d33d05..f9e26a0db028f01cb19e437f3fc277cacd4f1fd5 100644 --- a/src/plugins/wp/clabels.ml +++ b/src/plugins/wp/clabels.ml @@ -74,6 +74,11 @@ let of_logic = function | BuiltinLabel LoopEntry -> loopentry | StmtLabel s -> stmt !s +let is_post = function + | BuiltinLabel Post -> true + | FormalLabel a -> a = post + | _ -> false + let name = function FormalLabel a -> a | _ -> "" let lookup labels a = diff --git a/src/plugins/wp/clabels.mli b/src/plugins/wp/clabels.mli index 26bdbfb4fcbdce2eb8ea16e372f9147ba91b926e..33812ec5f1377b696943adbbdfbd50cb110555cf 100644 --- a/src/plugins/wp/clabels.mli +++ b/src/plugins/wp/clabels.mli @@ -65,6 +65,9 @@ val of_logic : Cil_types.logic_label -> c_label labels. Ambiguous labels are: Old, LoopEntry and LoopCurrent, since they points to different program points dependending on the context. *) +val is_post : Cil_types.logic_label -> bool +(** Checks whether the logic-label is [Post] or [to_logic post] *) + val pretty : Format.formatter -> c_label -> unit open Cil_types diff --git a/src/plugins/wp/normAtLabels.ml b/src/plugins/wp/normAtLabels.ml index bb41fa3dcc6df86fe0ec09c7535d61c721de45a2..197b12f968517c08056b5183ade17088df4863a3 100644 --- a/src/plugins/wp/normAtLabels.ml +++ b/src/plugins/wp/normAtLabels.ml @@ -210,9 +210,27 @@ let preproc_assigns labels asgns = let visitor = new norm_at labels in List.map (Visitor.visitFramacFrom visitor) asgns +let has_postassigns = function + | WritesAny -> false + | Writes froms -> + let exception HAS_POST in + let visitor = new norm_at (fun l -> + if Clabels.is_post l then raise HAS_POST + else Clabels.of_logic l + ) in + try + List.iter + (fun fr -> ignore @@ Visitor.visitFramacFrom visitor fr) + froms ; + false + with HAS_POST -> + true + let catch_label_error ex txt1 txt2 = match ex with | LabelError lab -> Wp_parameters.warning "Unexpected label %a in %s : ignored %s" Wp_error.pp_logic_label lab txt1 txt2 | _ -> raise ex + +(* -------------------------------------------------------------------------- *) diff --git a/src/plugins/wp/normAtLabels.mli b/src/plugins/wp/normAtLabels.mli index 14b653d70999ee5479a490f546d475601b2726df..0dd24f825450e8170399fcf7ab9f0de90b6fd320 100644 --- a/src/plugins/wp/normAtLabels.mli +++ b/src/plugins/wp/normAtLabels.mli @@ -42,5 +42,5 @@ val labels_predicate : (logic_label * logic_label) list -> label_mapping val labels_axiom : label_mapping val preproc_annot : label_mapping -> predicate -> predicate - val preproc_assigns : label_mapping -> from list -> from list +val has_postassigns : assigns -> bool diff --git a/src/plugins/wp/tests/wp_acsl/oracle/postassigns.res.oracle b/src/plugins/wp/tests/wp_acsl/oracle/postassigns.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..8abc928d33f1abe77a4033024acc964ece36ba7c --- /dev/null +++ b/src/plugins/wp/tests/wp_acsl/oracle/postassigns.res.oracle @@ -0,0 +1,230 @@ +# frama-c -wp [...] +[kernel] Parsing tests/wp_acsl/postassigns.c (with preprocessing) +[wp] Running WP plugin... +[wp] Warning: Missing RTE guards +------------------------------------------------------------ + Function job1 +------------------------------------------------------------ + +Goal Post-condition (file tests/wp_acsl/postassigns.c, line 4) in 'job1': +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 5) in 'job1' (1/9): +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 5) in 'job1' (2/9): +Effect at line 10 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 5) in 'job1' (3/9): +Effect at line 10 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 5) in 'job1' (4/9): +Effect at line 11 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 5) in 'job1' (5/9): +Effect at line 11 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 5) in 'job1' (6/9): +Effect at line 12 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 5) in 'job1' (7/9): +Effect at line 12 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 5) in 'job1' (8/9): +Effect at line 13 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 5) in 'job1' (9/9): +Effect at line 13 +Prove: true. + +------------------------------------------------------------ +------------------------------------------------------------ + Function job2 +------------------------------------------------------------ + +Goal Post-condition (file tests/wp_acsl/postassigns.c, line 19) in 'job2': +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 20) in 'job2' (1/9): +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 20) in 'job2' (2/9): +Effect at line 25 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 20) in 'job2' (3/9): +Effect at line 25 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 20) in 'job2' (4/9): +Effect at line 26 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 20) in 'job2' (5/9): +Effect at line 26 +Let x = A[1]. +Assume { + Type: is_sint32(x). + (* Heap *) + Type: (region(p.base) <= 0) /\ IsArray_sint32(A) /\ linked(Malloc_0). + (* Goal *) + When: !invalid(Malloc_0, shift_sint32(p, x), 1). +} +Prove: exists i : Z. (A[i] = x) /\ (0 <= i) /\ (i <= 3). + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 20) in 'job2' (6/9): +Effect at line 27 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 20) in 'job2' (7/9): +Effect at line 27 +Let x = A[2]. +Assume { + Type: is_sint32(x). + (* Heap *) + Type: (region(p.base) <= 0) /\ IsArray_sint32(A) /\ linked(Malloc_0). + (* Goal *) + When: !invalid(Malloc_0, shift_sint32(p, x), 1). +} +Prove: exists i : Z. (A[i] = x) /\ (0 <= i) /\ (i <= 3). + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 20) in 'job2' (8/9): +Effect at line 28 +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 20) in 'job2' (9/9): +Effect at line 28 +Prove: true. + +------------------------------------------------------------ +------------------------------------------------------------ + Function job3 +------------------------------------------------------------ + +Goal Preservation of Invariant (file tests/wp_acsl/postassigns.c, line 38): +Assume { + Type: is_sint32(N) /\ is_sint32(i) /\ is_sint32(1 + i). + (* Pre-condition *) + Have: 0 <= N. + (* Invariant *) + Have: (i <= N) /\ (0 <= i). + (* Then *) + Have: i < N. +} +Prove: (-1) <= i. + +------------------------------------------------------------ + +Goal Establishment of Invariant (file tests/wp_acsl/postassigns.c, line 38): +Prove: true. + +------------------------------------------------------------ + +Goal Loop assigns (file tests/wp_acsl/postassigns.c, line 39) (1/3): +Prove: true. + +------------------------------------------------------------ + +Goal Loop assigns (file tests/wp_acsl/postassigns.c, line 39) (2/3): +Effect at line 41 +Prove: true. + +------------------------------------------------------------ + +Goal Loop assigns (file tests/wp_acsl/postassigns.c, line 39) (3/3): +Effect at line 42 +Let a = shift_sint32(p, i). +Assume { + Type: is_sint32(N) /\ is_sint32(i). + (* Heap *) + Type: (region(p.base) <= 0) /\ linked(Malloc_0). + (* Goal *) + When: !invalid(Malloc_0, a, 1). + (* Pre-condition *) + Have: 0 <= N. + (* Invariant *) + Have: (i <= N) /\ (0 <= i). + (* Then *) + Have: i < N. +} +Prove: included(a, 1, shift_sint32(p, 0), N). + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 33) in 'job3' (1/2): +Prove: true. + +------------------------------------------------------------ + +Goal Assigns (file tests/wp_acsl/postassigns.c, line 33) in 'job3' (2/2): +Effect at line 41 +Prove: true. + +------------------------------------------------------------ +[wp] tests/wp_acsl/postassigns.c:7: Warning: + Memory model hypotheses for function 'job1': + /*@ + behavior wp_typed: + requires \separated(p + (..), &N); + ensures \separated(p + (0 .. \at(N,Post) - 1), &N); + */ + void job1(int *p); +[wp] tests/wp_acsl/postassigns.c:22: Warning: + Memory model hypotheses for function 'job2': + /*@ + behavior wp_typed: + requires \separated(p + (..), (int *)A + (..), &N); + ensures \separated(p + A[0 .. \at(N,Post) - 1], (int *)A + (..), &N); + */ + void job2(int *p); +[wp] tests/wp_acsl/postassigns.c:35: Warning: + Memory model hypotheses for function 'job3': + /*@ + behavior wp_typed: + requires \separated(p + (..), &N); + ensures \separated(p + (0 .. \at(N,Post)), &N); + */ + void job3(int *p); diff --git a/src/plugins/wp/tests/wp_acsl/oracle_qualif/postassigns.res.oracle b/src/plugins/wp/tests/wp_acsl/oracle_qualif/postassigns.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..ef70c9d2f6e56db04fc30ccefa62a3d4ac6c3ea5 --- /dev/null +++ b/src/plugins/wp/tests/wp_acsl/oracle_qualif/postassigns.res.oracle @@ -0,0 +1,65 @@ +# frama-c -wp [...] +[kernel] Parsing tests/wp_acsl/postassigns.c (with preprocessing) +[wp] Running WP plugin... +[wp] Warning: Missing RTE guards +[wp] 27 goals scheduled +[wp] [Qed] Goal typed_job1_ensures : Valid +[wp] [Qed] Goal typed_job1_assigns_part1 : Valid +[wp] [Qed] Goal typed_job1_assigns_part2 : Valid +[wp] [Qed] Goal typed_job1_assigns_part3 : Valid +[wp] [Qed] Goal typed_job1_assigns_part4 : Valid +[wp] [Qed] Goal typed_job1_assigns_part5 : Valid +[wp] [Qed] Goal typed_job1_assigns_part6 : Valid +[wp] [Qed] Goal typed_job1_assigns_part7 : Valid +[wp] [Qed] Goal typed_job1_assigns_part8 : Valid +[wp] [Qed] Goal typed_job1_assigns_part9 : Valid +[wp] [Qed] Goal typed_job2_ensures : Valid +[wp] [Qed] Goal typed_job2_assigns_part1 : Valid +[wp] [Qed] Goal typed_job2_assigns_part2 : Valid +[wp] [Qed] Goal typed_job2_assigns_part3 : Valid +[wp] [Qed] Goal typed_job2_assigns_part4 : Valid +[wp] [Alt-Ergo] Goal typed_job2_assigns_part5 : Valid +[wp] [Qed] Goal typed_job2_assigns_part6 : Valid +[wp] [Alt-Ergo] Goal typed_job2_assigns_part7 : Valid +[wp] [Qed] Goal typed_job2_assigns_part8 : Valid +[wp] [Qed] Goal typed_job2_assigns_part9 : Valid +[wp] [Alt-Ergo] Goal typed_job3_loop_invariant_preserved : Valid +[wp] [Qed] Goal typed_job3_loop_invariant_established : Valid +[wp] [Qed] Goal typed_job3_loop_assigns_part1 : Valid +[wp] [Qed] Goal typed_job3_loop_assigns_part2 : Valid +[wp] [Alt-Ergo] Goal typed_job3_loop_assigns_part3 : Valid +[wp] [Qed] Goal typed_job3_assigns_part1 : Valid +[wp] [Qed] Goal typed_job3_assigns_part2 : Valid +[wp] Proved goals: 27 / 27 + Qed: 23 + Alt-Ergo: 4 +------------------------------------------------------------ + Functions WP Alt-Ergo Total Success + job1 10 - 10 100% + job2 8 2 10 100% + job3 5 2 7 100% +------------------------------------------------------------ +[wp] tests/wp_acsl/postassigns.c:7: Warning: + Memory model hypotheses for function 'job1': + /*@ + behavior wp_typed: + requires \separated(p + (..), &N); + ensures \separated(p + (0 .. \at(N,Post) - 1), &N); + */ + void job1(int *p); +[wp] tests/wp_acsl/postassigns.c:22: Warning: + Memory model hypotheses for function 'job2': + /*@ + behavior wp_typed: + requires \separated(p + (..), (int *)A + (..), &N); + ensures \separated(p + A[0 .. \at(N,Post) - 1], (int *)A + (..), &N); + */ + void job2(int *p); +[wp] tests/wp_acsl/postassigns.c:35: Warning: + Memory model hypotheses for function 'job3': + /*@ + behavior wp_typed: + requires \separated(p + (..), &N); + ensures \separated(p + (0 .. \at(N,Post)), &N); + */ + void job3(int *p); diff --git a/src/plugins/wp/tests/wp_acsl/postassigns.c b/src/plugins/wp/tests/wp_acsl/postassigns.c new file mode 100644 index 0000000000000000000000000000000000000000..a2c1b7d1ba8ca26344e485d05bf64119cac34a0c --- /dev/null +++ b/src/plugins/wp/tests/wp_acsl/postassigns.c @@ -0,0 +1,44 @@ +int N; + +/*@ + ensures N == 4; + assigns N, p[0..\at(N,Post)-1]; +*/ +void job1(int *p) +{ + N = 0; + p[N++] = 0; + p[N++] = 0; + p[N++] = 0; + p[N++] = 0; +} + +int A[4]; + +/*@ + ensures N == 4; + assigns N, *(p + A[0..\at(N,Post)-1]); +*/ +void job2(int *p) +{ + N = 0; + p[A[N++]] = 0; + p[A[N++]] = 0; + p[A[N++]] = 0; + p[A[N++]] = 0; +} + +/*@ + requires 0 <= N; + assigns N, p[0..\at(N,Post)]; +*/ +void job3(int *p) +{ + /*@ + loop invariant 0 <= i <= N; + loop assigns i, p[0..N-1]; + */ + for (int i = 0; i < N; i++) + p[i] = 0; + N++; +}