From 7d0e9489b3e16c1999296940df13be84b5434d28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Virgile=20Pr=C3=A9vosto?= <virgile.prevosto@cea.fr> Date: Wed, 25 May 2011 16:02:21 +0000 Subject: [PATCH] [e-acsl] Fixing bug in handling of statement contracts (duplication of blocks) --- .../e-acsl-runtime/oracle/gen_stmt_contract.c | 59 +++++--- .../oracle/stmt_contract.res.oracle | 133 ++++++++++++++---- .../tests/e-acsl-runtime/stmt_contract.i | 10 +- src/plugins/e-acsl/visit.ml | 74 +++++----- 4 files changed, 186 insertions(+), 90 deletions(-) diff --git a/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/gen_stmt_contract.c b/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/gen_stmt_contract.c index a25ef89b8e5..9141713a57c 100644 --- a/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/gen_stmt_contract.c +++ b/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/gen_stmt_contract.c @@ -827,27 +827,50 @@ int main(void) } x += y; - /*@ requires x ≡ 5; - ensures x ≡ 5; */ + /*@ requires x ≡ 5; */ + /*@ requires y ≡ 2; */ + { mpz_t e_acsl_86; mpz_t e_acsl_87; int e_acsl_88; + __gmpz_init_set_si((__mpz_struct *)(e_acsl_86),(long)y); + __gmpz_init_set_si((__mpz_struct *)(e_acsl_87),(long)2); + e_acsl_88 = __gmpz_cmp((__mpz_struct const *)(e_acsl_86), + (__mpz_struct const *)(e_acsl_87)); + if (! (e_acsl_88 == 0)) { e_acsl_fail((char *)"(y == 2)"); } + __gmpz_clear((__mpz_struct *)(e_acsl_86)); + __gmpz_clear((__mpz_struct *)(e_acsl_87)); + } + + { mpz_t e_acsl_89; mpz_t e_acsl_90; int e_acsl_91; + __gmpz_init_set_si((__mpz_struct *)(e_acsl_89),(long)x); + __gmpz_init_set_si((__mpz_struct *)(e_acsl_90),(long)5); + e_acsl_91 = __gmpz_cmp((__mpz_struct const *)(e_acsl_89), + (__mpz_struct const *)(e_acsl_90)); + if (! (e_acsl_91 == 0)) { e_acsl_fail((char *)"(x == 5)"); } + __gmpz_clear((__mpz_struct *)(e_acsl_89)); + __gmpz_clear((__mpz_struct *)(e_acsl_90)); + } + + x += y; + /*@ requires x ≡ 7; + ensures x ≡ 7; */ { - { mpz_t e_acsl_86; mpz_t e_acsl_87; int e_acsl_88; - __gmpz_init_set_si((__mpz_struct *)(e_acsl_86),(long)x); - __gmpz_init_set_si((__mpz_struct *)(e_acsl_87),(long)5); - e_acsl_88 = __gmpz_cmp((__mpz_struct const *)(e_acsl_86), - (__mpz_struct const *)(e_acsl_87)); - if (! (e_acsl_88 == 0)) { e_acsl_fail((char *)"(x == 5)"); } - __gmpz_clear((__mpz_struct *)(e_acsl_86)); - __gmpz_clear((__mpz_struct *)(e_acsl_87)); + { mpz_t e_acsl_92; mpz_t e_acsl_93; int e_acsl_94; + __gmpz_init_set_si((__mpz_struct *)(e_acsl_92),(long)x); + __gmpz_init_set_si((__mpz_struct *)(e_acsl_93),(long)7); + e_acsl_94 = __gmpz_cmp((__mpz_struct const *)(e_acsl_92), + (__mpz_struct const *)(e_acsl_93)); + if (! (e_acsl_94 == 0)) { e_acsl_fail((char *)"(x == 7)"); } + __gmpz_clear((__mpz_struct *)(e_acsl_92)); + __gmpz_clear((__mpz_struct *)(e_acsl_93)); } __retres = 0; - { mpz_t e_acsl_89; mpz_t e_acsl_90; int e_acsl_91; - __gmpz_init_set_si((__mpz_struct *)(e_acsl_89),(long)x); - __gmpz_init_set_si((__mpz_struct *)(e_acsl_90),(long)5); - e_acsl_91 = __gmpz_cmp((__mpz_struct const *)(e_acsl_89), - (__mpz_struct const *)(e_acsl_90)); - if (! (e_acsl_91 == 0)) { e_acsl_fail((char *)"(x == 5)"); } - __gmpz_clear((__mpz_struct *)(e_acsl_89)); - __gmpz_clear((__mpz_struct *)(e_acsl_90)); + { mpz_t e_acsl_95; mpz_t e_acsl_96; int e_acsl_97; + __gmpz_init_set_si((__mpz_struct *)(e_acsl_95),(long)x); + __gmpz_init_set_si((__mpz_struct *)(e_acsl_96),(long)7); + e_acsl_97 = __gmpz_cmp((__mpz_struct const *)(e_acsl_95), + (__mpz_struct const *)(e_acsl_96)); + if (! (e_acsl_97 == 0)) { e_acsl_fail((char *)"(x == 7)"); } + __gmpz_clear((__mpz_struct *)(e_acsl_95)); + __gmpz_clear((__mpz_struct *)(e_acsl_96)); } } diff --git a/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/stmt_contract.res.oracle b/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/stmt_contract.res.oracle index 3f86f8c193f..489d27a1e0a 100644 --- a/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/stmt_contract.res.oracle +++ b/src/plugins/e-acsl/tests/e-acsl-runtime/oracle/stmt_contract.res.oracle @@ -483,16 +483,16 @@ PROJECT_FILE.i:246:[value] assigning non deterministic value for the first time Called from PROJECT_FILE.i:306. [value] Done for function mpz_clear [value] computing for function mpz_init_set_si <- main. - Called from PROJECT_FILE.i:314. + Called from PROJECT_FILE.i:313. [value] Done for function mpz_init_set_si [value] computing for function mpz_init_set_si <- main. - Called from PROJECT_FILE.i:314. + Called from PROJECT_FILE.i:313. [value] Done for function mpz_init_set_si [value] computing for function mpz_cmp <- main. - Called from PROJECT_FILE.i:315. + Called from PROJECT_FILE.i:314. [value] Done for function mpz_cmp [value] computing for function e_acsl_fail <- main. - Called from PROJECT_FILE.i:316. + Called from PROJECT_FILE.i:315. [value] computing for function printf <- e_acsl_fail <- main. Called from PROJECT_FILE.i:115. [value] Done for function printf @@ -502,22 +502,72 @@ PROJECT_FILE.i:246:[value] assigning non deterministic value for the first time [value] Recording results for e_acsl_fail [value] Done for function e_acsl_fail [value] computing for function mpz_clear <- main. - Called from PROJECT_FILE.i:317. + Called from PROJECT_FILE.i:316. [value] Done for function mpz_clear [value] computing for function mpz_clear <- main. - Called from PROJECT_FILE.i:317. + Called from PROJECT_FILE.i:316. [value] Done for function mpz_clear [value] computing for function mpz_init_set_si <- main. - Called from PROJECT_FILE.i:321. + Called from PROJECT_FILE.i:320. [value] Done for function mpz_init_set_si [value] computing for function mpz_init_set_si <- main. - Called from PROJECT_FILE.i:321. + Called from PROJECT_FILE.i:320. [value] Done for function mpz_init_set_si [value] computing for function mpz_cmp <- main. - Called from PROJECT_FILE.i:322. + Called from PROJECT_FILE.i:321. [value] Done for function mpz_cmp [value] computing for function e_acsl_fail <- main. + Called from PROJECT_FILE.i:322. +[value] computing for function printf <- e_acsl_fail <- main. + Called from PROJECT_FILE.i:115. +[value] Done for function printf +[value] computing for function exit <- e_acsl_fail <- main. + Called from PROJECT_FILE.i:115. +[value] Done for function exit +[value] Recording results for e_acsl_fail +[value] Done for function e_acsl_fail +[value] computing for function mpz_clear <- main. Called from PROJECT_FILE.i:323. +[value] Done for function mpz_clear +[value] computing for function mpz_clear <- main. + Called from PROJECT_FILE.i:323. +[value] Done for function mpz_clear +[value] computing for function mpz_init_set_si <- main. + Called from PROJECT_FILE.i:331. +[value] Done for function mpz_init_set_si +[value] computing for function mpz_init_set_si <- main. + Called from PROJECT_FILE.i:331. +[value] Done for function mpz_init_set_si +[value] computing for function mpz_cmp <- main. + Called from PROJECT_FILE.i:332. +[value] Done for function mpz_cmp +[value] computing for function e_acsl_fail <- main. + Called from PROJECT_FILE.i:333. +[value] computing for function printf <- e_acsl_fail <- main. + Called from PROJECT_FILE.i:115. +[value] Done for function printf +[value] computing for function exit <- e_acsl_fail <- main. + Called from PROJECT_FILE.i:115. +[value] Done for function exit +[value] Recording results for e_acsl_fail +[value] Done for function e_acsl_fail +[value] computing for function mpz_clear <- main. + Called from PROJECT_FILE.i:334. +[value] Done for function mpz_clear +[value] computing for function mpz_clear <- main. + Called from PROJECT_FILE.i:334. +[value] Done for function mpz_clear +[value] computing for function mpz_init_set_si <- main. + Called from PROJECT_FILE.i:338. +[value] Done for function mpz_init_set_si +[value] computing for function mpz_init_set_si <- main. + Called from PROJECT_FILE.i:338. +[value] Done for function mpz_init_set_si +[value] computing for function mpz_cmp <- main. + Called from PROJECT_FILE.i:339. +[value] Done for function mpz_cmp +[value] computing for function e_acsl_fail <- main. + Called from PROJECT_FILE.i:340. [value] computing for function printf <- e_acsl_fail <- main. Called from PROJECT_FILE.i:115. [value] Done for function printf @@ -527,10 +577,10 @@ PROJECT_FILE.i:246:[value] assigning non deterministic value for the first time [value] Recording results for e_acsl_fail [value] Done for function e_acsl_fail [value] computing for function mpz_clear <- main. - Called from PROJECT_FILE.i:324. + Called from PROJECT_FILE.i:341. [value] Done for function mpz_clear [value] computing for function mpz_clear <- main. - Called from PROJECT_FILE.i:324. + Called from PROJECT_FILE.i:341. [value] Done for function mpz_clear [value] Recording results for main [value] done for function main @@ -539,7 +589,7 @@ PROJECT_FILE.i:246:[value] assigning non deterministic value for the first time NON TERMINATING FUNCTION [value] Values for function main: __retres ∈ {0} - x ∈ {5} + x ∈ {7} y ∈ {2} /* Generated by Frama-C */ struct __anonstruct___mpz_struct_1 { @@ -835,27 +885,50 @@ int main(void) } x += y; - /*@ requires x ≡ 5; - ensures x ≡ 5; */ + /*@ requires x ≡ 5; */ + /*@ requires y ≡ 2; */ + { mpz_t e_acsl_86; mpz_t e_acsl_87; int e_acsl_88; + mpz_init_set_si((__mpz_struct *)(e_acsl_86),(long)y); + mpz_init_set_si((__mpz_struct *)(e_acsl_87),(long)2); + e_acsl_88 = mpz_cmp((__mpz_struct const *)(e_acsl_86), + (__mpz_struct const *)(e_acsl_87)); + if (! (e_acsl_88 == 0)) { e_acsl_fail((char *)"(y == 2)"); } + mpz_clear((__mpz_struct *)(e_acsl_86)); + mpz_clear((__mpz_struct *)(e_acsl_87)); + } + + { mpz_t e_acsl_89; mpz_t e_acsl_90; int e_acsl_91; + mpz_init_set_si((__mpz_struct *)(e_acsl_89),(long)x); + mpz_init_set_si((__mpz_struct *)(e_acsl_90),(long)5); + e_acsl_91 = mpz_cmp((__mpz_struct const *)(e_acsl_89), + (__mpz_struct const *)(e_acsl_90)); + if (! (e_acsl_91 == 0)) { e_acsl_fail((char *)"(x == 5)"); } + mpz_clear((__mpz_struct *)(e_acsl_89)); + mpz_clear((__mpz_struct *)(e_acsl_90)); + } + + x += y; + /*@ requires x ≡ 7; + ensures x ≡ 7; */ { - { mpz_t e_acsl_86; mpz_t e_acsl_87; int e_acsl_88; - mpz_init_set_si((__mpz_struct *)(e_acsl_86),(long)x); - mpz_init_set_si((__mpz_struct *)(e_acsl_87),(long)5); - e_acsl_88 = mpz_cmp((__mpz_struct const *)(e_acsl_86), - (__mpz_struct const *)(e_acsl_87)); - if (! (e_acsl_88 == 0)) { e_acsl_fail((char *)"(x == 5)"); } - mpz_clear((__mpz_struct *)(e_acsl_86)); - mpz_clear((__mpz_struct *)(e_acsl_87)); + { mpz_t e_acsl_92; mpz_t e_acsl_93; int e_acsl_94; + mpz_init_set_si((__mpz_struct *)(e_acsl_92),(long)x); + mpz_init_set_si((__mpz_struct *)(e_acsl_93),(long)7); + e_acsl_94 = mpz_cmp((__mpz_struct const *)(e_acsl_92), + (__mpz_struct const *)(e_acsl_93)); + if (! (e_acsl_94 == 0)) { e_acsl_fail((char *)"(x == 7)"); } + mpz_clear((__mpz_struct *)(e_acsl_92)); + mpz_clear((__mpz_struct *)(e_acsl_93)); } __retres = 0; - { mpz_t e_acsl_89; mpz_t e_acsl_90; int e_acsl_91; - mpz_init_set_si((__mpz_struct *)(e_acsl_89),(long)x); - mpz_init_set_si((__mpz_struct *)(e_acsl_90),(long)5); - e_acsl_91 = mpz_cmp((__mpz_struct const *)(e_acsl_89), - (__mpz_struct const *)(e_acsl_90)); - if (! (e_acsl_91 == 0)) { e_acsl_fail((char *)"(x == 5)"); } - mpz_clear((__mpz_struct *)(e_acsl_89)); - mpz_clear((__mpz_struct *)(e_acsl_90)); + { mpz_t e_acsl_95; mpz_t e_acsl_96; int e_acsl_97; + mpz_init_set_si((__mpz_struct *)(e_acsl_95),(long)x); + mpz_init_set_si((__mpz_struct *)(e_acsl_96),(long)7); + e_acsl_97 = mpz_cmp((__mpz_struct const *)(e_acsl_95), + (__mpz_struct const *)(e_acsl_96)); + if (! (e_acsl_97 == 0)) { e_acsl_fail((char *)"(x == 7)"); } + mpz_clear((__mpz_struct *)(e_acsl_95)); + mpz_clear((__mpz_struct *)(e_acsl_96)); } } diff --git a/src/plugins/e-acsl/tests/e-acsl-runtime/stmt_contract.i b/src/plugins/e-acsl/tests/e-acsl-runtime/stmt_contract.i index 60314cece3d..eb443f78b14 100644 --- a/src/plugins/e-acsl/tests/e-acsl-runtime/stmt_contract.i +++ b/src/plugins/e-acsl/tests/e-acsl-runtime/stmt_contract.i @@ -39,11 +39,11 @@ int main(void) { x = x + y; // TODO: break the CFG and I don't know why :( - /* /\*@ requires x == 3; *\/ */ - /* /\*@ requires y == 2; *\/ */ - /* x = x + y; */ + /*@ requires x == 5; */ + /*@ requires y == 2; */ + x = x + y; - /*@ requires x == 5; - @ ensures x == 5; */ + /*@ requires x == 7; + @ ensures x == 7; */ return 0; } diff --git a/src/plugins/e-acsl/visit.ml b/src/plugins/e-acsl/visit.ml index a3c201b31fb..0e72131f5b7 100644 --- a/src/plugins/e-acsl/visit.ml +++ b/src/plugins/e-acsl/visit.ml @@ -269,36 +269,32 @@ let rec named_predicate_to_exp env p = statement (if any) for runtime assertion checking *) (* ************************************************************************** *) -let convert_preconditions only_behaviors env behaviors = +let convert_preconditions env behaviors = let do_behavior env b = - if only_behaviors = [] || List.mem b.b_name only_behaviors then begin - let assumes_pred = - List.fold_left - (fun acc p -> Logic_const.pand (acc, Logic_const.unamed p.ip_content)) - Logic_const.ptrue - b.b_assumes - in + let assumes_pred = List.fold_left - (fun env p -> - let p = - Logic_const.pimplies (assumes_pred, Logic_const.unamed p.ip_content) - in - let e, env = named_predicate_to_exp env p in - Env.add_stmt env (Misc.mk_e_acsl_guard ~reverse:true e p)) - env - b.b_requires - end else + (fun acc p -> Logic_const.pand (acc, Logic_const.unamed p.ip_content)) + Logic_const.ptrue + b.b_assumes + in + List.fold_left + (fun env p -> + let p = + Logic_const.pimplies (assumes_pred, Logic_const.unamed p.ip_content) + in + let e, env = named_predicate_to_exp env p in + Env.add_stmt env (Misc.mk_e_acsl_guard ~reverse:true e p)) env + b.b_requires in List.fold_left do_behavior env behaviors -let convert_postconditions only_behaviors env behaviors = +let convert_postconditions env behaviors = (* generate one guard by postcondition of each behavior *) let do_behavior env b = - if only_behaviors = [] || List.mem b.b_name only_behaviors then begin - List.fold_left - (fun env (t, p) -> - match t with + List.fold_left + (fun env (t, p) -> + match t with | Normal -> let p = p.ip_content in if p <> Ptrue && b.b_assumes <> [] then @@ -308,35 +304,36 @@ let convert_postconditions only_behaviors env behaviors = Env.add_stmt env (Misc.mk_e_acsl_guard ~reverse:true e p) | Exits | Breaks | Continues | Returns -> Misc.not_yet "abnormal termination case in behavior") - env - b.b_post_cond - end else env + b.b_post_cond in List.fold_left do_behavior env behaviors -let convert_behaviors only_behaviors env behaviors = +let convert_behaviors env behaviors = List.iter (fun b -> if b.b_assigns <> WritesAny then Misc.not_yet "assigns clause in behavior"; if b.b_extended <> [] then Misc.not_yet "grammar extensions in behavior") behaviors; - let pre_env = convert_preconditions only_behaviors env behaviors in + let pre_env = + convert_preconditions (Env.no_overlap ~from:env Env.empty) behaviors + in let post_env = - convert_postconditions - only_behaviors (Env.no_overlap ~from:pre_env env) behaviors + convert_postconditions (Env.no_overlap ~from:pre_env Env.empty) behaviors in + let env = Env.merge_function_vars ~from:pre_env env in + let env = Env.merge_function_vars ~from:post_env env in Env.close_block_option pre_env, Env.close_block_option post_env, - Env.merge_function_vars ~from:post_env pre_env + env -let convert_spec only_behaviors env spec = +let convert_spec env spec = if spec.spec_variant <> None then Misc.not_yet "variant clause"; if spec.spec_terminates <> None then Misc.not_yet "terminates clause"; if spec.spec_complete_behaviors <> [] then Misc.not_yet "complete behaviors"; if spec.spec_disjoint_behaviors <> [] then Misc.not_yet "disjoint behaviors"; - convert_behaviors only_behaviors env spec.spec_behavior + convert_behaviors env spec.spec_behavior let convert_named_predicate env p = let e, env = named_predicate_to_exp env p in @@ -349,9 +346,11 @@ let convert_annotation env annot = | AAssert(l, p) -> if l <> [] then Misc.not_yet "assertions applied only on some behaviors"; convert_named_predicate env p, None - | AStmtSpec(only_behaviors, spec) -> - let pre_block, post_block, new_env = - convert_spec only_behaviors env spec + | AStmtSpec(l, spec) -> + if l <> [] then + Misc.not_yet "statement contract applied only on some behaviors"; + let pre_block, post_block, new_env = + convert_spec env spec in let env = Env.merge_function_vars ~from:new_env env in let env = match pre_block with @@ -405,7 +404,7 @@ class e_acsl_visitor prj generate = object (self) try let kf = Globals.Functions.get vi in let pre_b, post_b, env = - convert_spec [] Env.empty (Kernel_function.get_spec kf) + convert_spec Env.empty (Kernel_function.get_spec kf) in pre_block <- pre_b; post_block <- post_b; @@ -432,7 +431,8 @@ class e_acsl_visitor prj generate = object (self) let env, post_block = convert_rooted env ba in let post_stmts = match post_block with | None -> post_stmts - | Some b -> mkStmt ~valid_sid:true (Block b) :: post_stmts + | Some b -> + mkStmt ~valid_sid:true (Block b) :: post_stmts in env, post_stmts) stmt -- GitLab