diff --git a/src/plugins/wp/tests/wp_plugin/doomed_unreach.i b/src/plugins/wp/tests/wp_plugin/doomed_unreach.i new file mode 100644 index 0000000000000000000000000000000000000000..6327fad4ec08aa62ba356fd50696547c3400b4c9 --- /dev/null +++ b/src/plugins/wp/tests/wp_plugin/doomed_unreach.i @@ -0,0 +1,24 @@ +/* run.config + DONTRUN: + */ + +/* run.config_qualif + OPT: -wp-smoke-tests -wp-steps 100 +*/ + +//@ assigns \result; +int job(int x) { + switch(x) { + return 42; + case 0: + return 0; + case 1: + return 1; + x = 42; + return 42; + default: + return 3; + } + x = 42; + return 42; +} diff --git a/src/plugins/wp/tests/wp_plugin/oracle_qualif/doomed_unreach.res.oracle b/src/plugins/wp/tests/wp_plugin/oracle_qualif/doomed_unreach.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..7140362d3548372aa5cbc7e8ff1bc89cf34acbf4 --- /dev/null +++ b/src/plugins/wp/tests/wp_plugin/oracle_qualif/doomed_unreach.res.oracle @@ -0,0 +1,21 @@ +# frama-c -wp -wp-steps 100 [...] +[kernel] Parsing tests/wp_plugin/doomed_unreach.i (no preprocessing) +[wp] Running WP plugin... +[wp] tests/wp_plugin/doomed_unreach.i:12: Warning: Failed smoke-test +[wp] tests/wp_plugin/doomed_unreach.i:17: Warning: Failed smoke-test +[wp] tests/wp_plugin/doomed_unreach.i:22: Warning: Failed smoke-test +[wp] Warning: Missing RTE guards +[wp] 6 goals scheduled +[wp] [Passed] Smoke-test typed_job_wp_smoke_dead_code_s4 +[wp] [Passed] Smoke-test typed_job_wp_smoke_dead_code_s5 +[wp] [Passed] Smoke-test typed_job_wp_smoke_dead_code_s8 +[wp] [Qed] Goal typed_job_assigns_part1 : Valid +[wp] [Qed] Goal typed_job_assigns_part2 : Valid +[wp] [Qed] Goal typed_job_assigns_part3 : Valid +[wp] Proved goals: 6 / 9 + Qed: 3 + Alt-Ergo: 3 +------------------------------------------------------------ + Functions WP Alt-Ergo Total Success + job 3 3 6 100% +------------------------------------------------------------ diff --git a/src/plugins/wp/wpAnnot.ml b/src/plugins/wp/wpAnnot.ml index ad7739a514330aa32acee7cb455161c4541bd0a5..4a8f6ea3aeadb06a0fde85baa9c1bc075daec05b 100644 --- a/src/plugins/wp/wpAnnot.ml +++ b/src/plugins/wp/wpAnnot.ml @@ -1294,7 +1294,7 @@ class vexit kf acc = Cil.DoChildren end -let process_unreached_annots cfg = +let process_unreached_annots cfg reachability = debug "collecting unreachable annotations@."; let unreached = Cil2cfg.unreachable_nodes cfg in let kf = Cil2cfg.cfg_kf cfg in @@ -1311,7 +1311,15 @@ let process_unreached_annots cfg = List.fold_left add_id acc (WpPropId.mk_code_annot_ids kf s a) in let do_stmt s acc = - Annotations.fold_code_annot (do_annot s) s acc in + let acc = + match reachability with + | None -> acc + | Some r -> + if WpReached.smoking r s then + WpPropId.mk_smoke kf ~id:"unreachable" ~unreachable:s () :: acc + else acc + in Annotations.fold_code_annot (do_annot s) s acc + in let do_node acc n = debug "process annotations of unreachable node %a@." @@ -1364,7 +1372,7 @@ let build_configs assigns kf model behaviors ki property = && Wp_parameters.SmokeDeadcode.get () then Some (WpReached.reachability kf) else None in - process_unreached_annots cfg ; + process_unreached_annots cfg reachability ; let def_annot_bhv, bhvs = find_behaviors kf cfg ki behaviors in if bhvs <> [] then debug "[get_strategies] %d behaviors" (List.length bhvs); let mk_bhv_config bhv = { diff --git a/src/plugins/wp/wpReached.ml b/src/plugins/wp/wpReached.ml index faa8f4fa17349e6af2a4f7fa3392ea0763f4018a..60fe40d175ef9651652217627cc829397fddd8c9 100644 --- a/src/plugins/wp/wpReached.ml +++ b/src/plugins/wp/wpReached.ml @@ -40,15 +40,20 @@ type node = { id : int ; mutable flow : flow ; mutable prev : node list ; - mutable reached : bool option ; - mutable alive : bool option ; + mutable protected : bool option ; + (* whether the node is dominated by unreachable node or by a smoke test *) + mutable unreachable : bool option ; + (* whether the node is unreachable from the entry point *) } let kid = ref 0 let node () = incr kid ; - { id = !kid ; prev = [] ; alive = None ; reached = None ; flow = F_goto } + { id = !kid ; prev = [] ; + protected = None ; + unreachable = None ; + flow = F_goto } (* -------------------------------------------------------------------------- *) (* --- Unrolled Loop --- *) @@ -175,46 +180,46 @@ and sequence env seq b = match seq with (* --- Compute Reachability --- *) (* -------------------------------------------------------------------------- *) -let rec reached node = - match node.reached with +let rec unreachable node = + match node.unreachable with | Some r -> r | None -> - node.reached <- Some true ; (* cut loops *) + node.unreachable <- Some true ; (* cut loops *) let r = match node.flow with - | F_dead | F_entry -> true + | F_dead -> true + | F_entry -> false | F_goto | F_effect | F_return | F_branch | F_call -> - List.for_all reached_after node.prev - in - node.reached <- Some r ; r - -and reached_after node = - match node.flow with - | F_goto -> reached node - | F_effect | F_entry | F_dead -> true - | F_return | F_branch | F_call -> false + List.for_all unreachable node.prev + in node.unreachable <- Some r ; r -let rec alive node = - match node.alive with - | Some a -> a +let rec protected node = + match node.protected with + | Some r -> r | None -> - match node.flow with - | F_dead -> false - | F_entry -> true - | _ -> - node.alive <- Some false ; - let a = List.exists alive node.prev in - node.alive <- Some a ; a + node.protected <- Some false ; (* cut loops *) + let r = + match node.flow with + | F_dead | F_entry -> true + | F_goto | F_effect | F_return | F_branch | F_call -> + node.prev <> [] && List.for_all protected_by node.prev + in node.protected <- Some r ; r + +and protected_by prev = + match prev.flow with + | F_dead | F_entry | F_effect -> true + | F_goto -> protected prev + | F_call | F_branch | F_return -> unreachable prev let smoking_node n = match n.flow with - | F_effect | F_call | F_return -> alive n && not (reached n) + | F_effect | F_call | F_return -> not (protected n) | F_goto | F_branch | F_entry | F_dead -> false (* returns true if the stmt requires a reachability smoke test *) let smoking reachability stmt = try Stmt.Map.find stmt reachability |> smoking_node - with Not_found -> false + with Not_found -> true let compute kf = try @@ -245,14 +250,10 @@ let dump ~dir kf reached = N.define dot (fun a na -> let attr = - if smoking_node a - then [`Filled;`Fillcolor "orange"] - else - match a.flow with - | F_entry | F_effect | F_return | F_call -> - [`Filled;`Fillcolor "green"] - | F_dead -> [`Filled;`Fillcolor "red"] - | F_branch | F_goto -> [] + if smoking_node a then [`Filled;`Fillcolor "orange"] + else if protected a then [`Filled;`Fillcolor "green"] + else if unreachable a then [`Filled;`Fillcolor "red"] + else [] in G.node dot na attr ; List.iter (fun b ->