Skip to content
Snippets Groups Projects
Commit e5e0f11a authored by Loïc Correnson's avatar Loïc Correnson
Browse files

[wp] fix corner cases for unreachability

parent 61445a7d
No related branches found
No related tags found
No related merge requests found
...@@ -238,7 +238,7 @@ module HdefAnnotBhv = Cil2cfg.HE (struct type t = (stmt * int) end) ...@@ -238,7 +238,7 @@ module HdefAnnotBhv = Cil2cfg.HE (struct type t = (stmt * int) end)
type strategy_info = { type strategy_info = {
kf : Kernel_function.t; kf : Kernel_function.t;
cfg : Cil2cfg.t; cfg : Cil2cfg.t;
reached : WpReached.reached option ; reachability : WpReached.reachability option ;
cur_bhv : asked_bhv; cur_bhv : asked_bhv;
asked_bhvs : asked_bhv list; asked_bhvs : asked_bhv list;
asked_prop : asked_prop; asked_prop : asked_prop;
...@@ -915,7 +915,7 @@ let get_loop_annots config vloop s = ...@@ -915,7 +915,7 @@ let get_loop_annots config vloop s =
let add_stmt_deadcode_smoke config acc s = let add_stmt_deadcode_smoke config acc s =
if cur_fct_default_bhv config if cur_fct_default_bhv config
then then
match config.reached with match config.reachability with
| Some r when WpReached.smoking r s -> | Some r when WpReached.smoking r s ->
WpStrategy.add_prop_dead_code acc config.kf s WpStrategy.add_prop_dead_code acc config.kf s
| _ -> acc | _ -> acc
...@@ -1298,6 +1298,8 @@ let process_unreached_annots cfg = ...@@ -1298,6 +1298,8 @@ let process_unreached_annots cfg =
let do_annot s _ a acc = let do_annot s _ a acc =
List.fold_left add_id acc (WpPropId.mk_code_annot_ids kf s a) List.fold_left add_id acc (WpPropId.mk_code_annot_ids kf s a)
in in
let do_stmt s acc =
Annotations.fold_code_annot (do_annot s) s acc in
let do_node acc n = let do_node acc n =
debug debug
"process annotations of unreachable node %a@." "process annotations of unreachable node %a@."
...@@ -1312,13 +1314,13 @@ let process_unreached_annots cfg = ...@@ -1312,13 +1314,13 @@ let process_unreached_annots cfg =
ignore Visitor.(visitFramacKf (visitor :> frama_c_visitor) kf) ; ignore Visitor.(visitFramacKf (visitor :> frama_c_visitor) kf) ;
visitor#acc visitor#acc
| Cil2cfg.Vcall (s, _, call, _) -> | Cil2cfg.Vcall (s, _, call, _) ->
Annotations.fold_code_annot (do_annot s) s acc @ do_stmt s acc @
preconditions_at_call s call preconditions_at_call s call
| Cil2cfg.Vstmt s | Cil2cfg.Vstmt s
| Cil2cfg.VblkIn (Cil2cfg.Bstmt s, _) | Cil2cfg.VblkIn (Cil2cfg.Bstmt s, _)
| Cil2cfg.VblkOut (Cil2cfg.Bstmt s, _) | Cil2cfg.VblkOut (Cil2cfg.Bstmt s, _)
| Cil2cfg.Vtest (true, s, _) | Cil2cfg.Vloop (_, s) | Cil2cfg.Vswitch (s,_) | Cil2cfg.Vtest (true, s, _) | Cil2cfg.Vloop (_, s) | Cil2cfg.Vswitch (s,_)
-> Annotations.fold_code_annot (do_annot s) s acc -> do_stmt s acc
| Cil2cfg.Vtest (false, _, _) | Cil2cfg.Vloop2 _ | Cil2cfg.Vtest (false, _, _) | Cil2cfg.Vloop2 _
| Cil2cfg.VblkIn _ | Cil2cfg.VblkOut _ | Cil2cfg.Vend -> acc | Cil2cfg.VblkIn _ | Cil2cfg.VblkOut _ | Cil2cfg.Vend -> acc
in in
...@@ -1330,11 +1332,6 @@ let process_unreached_annots cfg = ...@@ -1330,11 +1332,6 @@ let process_unreached_annots cfg =
(* Everything must go through here. *) (* Everything must go through here. *)
(*----------------------------------------------------------------------------*) (*----------------------------------------------------------------------------*)
let get_cfg kf model =
if Wp_parameters.RTE.get () then WpRTE.generate model kf ;
let cfg = Cil2cfg.get kf in
let _ = process_unreached_annots cfg in cfg
let build_configs assigns kf model behaviors ki property = let build_configs assigns kf model behaviors ki property =
debug "[get_strategies] for behaviors names: %a@." debug "[get_strategies] for behaviors names: %a@."
(Wp_error.pp_string_list ~sep:" " ~empty:"<none>") (Wp_error.pp_string_list ~sep:" " ~empty:"<none>")
...@@ -1348,16 +1345,18 @@ let build_configs assigns kf model behaviors ki property = ...@@ -1348,16 +1345,18 @@ let build_configs assigns kf model behaviors ki property =
debug debug
"[get_strategies] select stmt %d properties@." s.sid "[get_strategies] select stmt %d properties@." s.sid
in in
let cfg = get_cfg kf model in if Wp_parameters.RTE.get () then WpRTE.generate model kf ;
let reached = let cfg = Cil2cfg.get kf in
let reachability =
if Wp_parameters.SmokeTests.get () if Wp_parameters.SmokeTests.get ()
&& Wp_parameters.SmokeDeadcode.get () && Wp_parameters.SmokeDeadcode.get ()
then Some (WpReached.reached kf) then Some (WpReached.reachability kf)
else None in else None in
process_unreached_annots cfg ;
let def_annot_bhv, bhvs = find_behaviors kf cfg ki behaviors in let def_annot_bhv, bhvs = find_behaviors kf cfg ki behaviors in
if bhvs <> [] then debug "[get_strategies] %d behaviors" (List.length bhvs); if bhvs <> [] then debug "[get_strategies] %d behaviors" (List.length bhvs);
let mk_bhv_config bhv = { let mk_bhv_config bhv = {
kf; reached; cfg; kf; reachability; cfg;
cur_bhv = bhv; cur_bhv = bhv;
asked_prop = property; asked_prop = property;
asked_bhvs = bhvs; asked_bhvs = bhvs;
......
...@@ -41,13 +41,14 @@ type node = { ...@@ -41,13 +41,14 @@ type node = {
mutable flow : flow ; mutable flow : flow ;
mutable prev : node list ; mutable prev : node list ;
mutable reached : bool option ; mutable reached : bool option ;
mutable alive : bool option ;
} }
let kid = ref 0 let kid = ref 0
let node () = let node () =
incr kid ; incr kid ;
{ id = !kid ; prev = [] ; reached = None ; flow = F_goto } { id = !kid ; prev = [] ; alive = None ; reached = None ; flow = F_goto }
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
(* --- Unrolled Loop --- *) (* --- Unrolled Loop --- *)
...@@ -83,7 +84,7 @@ let rec is_predicate cond p = ...@@ -83,7 +84,7 @@ let rec is_predicate cond p =
let is_dead_annot ca = let is_dead_annot ca =
match ca.annot_content with match ca.annot_content with
| APragma (Loop_pragma (Unroll_specs [ spec ; _ ])) -> | APragma (Loop_pragma (Unroll_specs [ spec ; _ ])) ->
false && is_unrolled_completely spec is_unrolled_completely spec
| AAssert([],p) | AAssert([],p)
| AInvariant([],_,p) -> | AInvariant([],_,p) ->
not p.tp_only_check && is_predicate false p.tp_statement not p.tp_only_check && is_predicate false p.tp_statement
...@@ -102,8 +103,8 @@ let is_dead_code stmt = ...@@ -102,8 +103,8 @@ let is_dead_code stmt =
(* --- Compute CFG --- *) (* --- Compute CFG --- *)
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
type reached = node Stmt.Map.t type reachability = node Stmt.Map.t
type cfg = reached ref type cfg = reachability ref (* working cfg during compilation *)
let of_stmt cfg s = let of_stmt cfg s =
try Stmt.Map.find s !cfg with Not_found -> try Stmt.Map.find s !cfg with Not_found ->
...@@ -133,11 +134,8 @@ type env = { ...@@ -133,11 +134,8 @@ type env = {
let rec stmt env s b = let rec stmt env s b =
let a = of_stmt env.cfg s in let a = of_stmt env.cfg s in
if is_dead_code s then let f = skind env a b s.skind in
a.flow <- F_dead a.flow <- if is_dead_code s then F_dead else f ; a
else
a.flow <- skind env a b s.skind ;
a
and skind env a b = function and skind env a b = function
| Instr i -> flow i (goto a b) | Instr i -> flow i (goto a b)
...@@ -182,7 +180,12 @@ let rec reached node = ...@@ -182,7 +180,12 @@ let rec reached node =
| Some r -> r | Some r -> r
| None -> | None ->
node.reached <- Some true ; (* cut loops *) node.reached <- Some true ; (* cut loops *)
let r = List.for_all reached_after node.prev in let r =
match node.flow with
| F_dead | F_entry -> true
| F_goto | F_effect | F_return | F_branch | F_call ->
List.for_all reached_after node.prev
in
node.reached <- Some r ; r node.reached <- Some r ; r
and reached_after node = and reached_after node =
...@@ -191,14 +194,26 @@ and reached_after node = ...@@ -191,14 +194,26 @@ and reached_after node =
| F_effect | F_entry | F_dead -> true | F_effect | F_entry | F_dead -> true
| F_return | F_branch | F_call -> false | F_return | F_branch | F_call -> false
let rec alive node =
match node.alive with
| Some a -> a
| 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
let smoking_node n = let smoking_node n =
match n.flow with match n.flow with
| F_effect | F_call | F_return -> not (reached n) | F_effect | F_call | F_return -> alive n && not (reached n)
| F_goto | F_branch | F_entry | F_dead -> false | F_goto | F_branch | F_entry | F_dead -> false
(* returns true if the stmt requires a reachability smoke test *) (* returns true if the stmt requires a reachability smoke test *)
let smoking nodes stmt = let smoking reachability stmt =
try Stmt.Map.find stmt nodes |> smoking_node try Stmt.Map.find stmt reachability |> smoking_node
with Not_found -> false with Not_found -> false
let compute kf = let compute kf =
...@@ -262,7 +277,8 @@ let dump ~dir kf reached = ...@@ -262,7 +277,8 @@ let dump ~dir kf reached =
| UnspecifiedSequence _ -> Printf.sprintf "Seq. s%d" s.sid | UnspecifiedSequence _ -> Printf.sprintf "Seq. s%d" s.sid
| Throw _ | TryExcept _ | TryCatch _ | TryFinally _ -> | Throw _ | TryExcept _ | TryCatch _ | TryFinally _ ->
Printf.sprintf "Exn. s%d" s.sid Printf.sprintf "Exn. s%d" s.sid
in G.node dot (N.get n) [`Box;`Label label]) in G.node dot (N.get n)
[`Box;`Label (Printf.sprintf "s%d n%d: %s" s.sid n.id label)])
reached ; reached ;
G.run dot ; G.run dot ;
G.close dot ; G.close dot ;
...@@ -276,7 +292,7 @@ let dump ~dir kf reached = ...@@ -276,7 +292,7 @@ let dump ~dir kf reached =
module FRmap = Kernel_function.Make_Table module FRmap = Kernel_function.Make_Table
(Datatype.Make (Datatype.Make
(struct (struct
type t = reached type t = reachability
include Datatype.Serializable_undefined include Datatype.Serializable_undefined
let reprs = [Stmt.Map.empty] let reprs = [Stmt.Map.empty]
let name = "WpReachable.reached" let name = "WpReachable.reached"
...@@ -289,7 +305,7 @@ module FRmap = Kernel_function.Make_Table ...@@ -289,7 +305,7 @@ module FRmap = Kernel_function.Make_Table
let dkey = Wp_parameters.register_category "reached" let dkey = Wp_parameters.register_category "reached"
let reached = FRmap.memo let reachability = FRmap.memo
begin fun kf -> begin fun kf ->
let r = compute kf in let r = compute kf in
(if Wp_parameters.has_dkey dkey then (if Wp_parameters.has_dkey dkey then
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
open Cil_types open Cil_types
type reached type reachability
(** control flow graph dedicated to smoke tests *) (** control flow graph dedicated to smoke tests *)
val is_predicate : bool -> predicate -> bool val is_predicate : bool -> predicate -> bool
...@@ -39,14 +39,14 @@ val is_dead_annot : code_annotation -> bool ...@@ -39,14 +39,14 @@ val is_dead_annot : code_annotation -> bool
val is_dead_code : stmt -> bool val is_dead_code : stmt -> bool
(** Checks whether the stmt has a dead-code annotation. *) (** Checks whether the stmt has a dead-code annotation. *)
val reached : Kernel_function.t -> reached val reachability : Kernel_function.t -> reachability
(** memoized reached cfg for function *) (** memoized reached cfg for function *)
val smoking : reached -> Cil_types.stmt -> bool val smoking : reachability -> Cil_types.stmt -> bool
(** Returns whether a stmt need a smoke tests to avoid being unreachable. (** Returns whether a stmt need a smoke tests to avoid being unreachable.
This is restricted to assignments, returns and calls not dominated This is restricted to assignments, returns and calls not dominated
another smoking statement. *) another smoking statement. *)
val dump : dir:Datatype.Filepath.t -> Kernel_function.t -> reached -> unit val dump : dir:Datatype.Filepath.t -> Kernel_function.t -> reachability -> unit
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment