You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
3.0 KiB
115 lines
3.0 KiB
10 years ago
|
(*
|
||
|
* Copyright (c) 2013 - Facebook. All rights reserved.
|
||
|
*)
|
||
|
|
||
|
module L = Logging
|
||
|
module F = Format
|
||
|
open Utils
|
||
|
open Dataflow
|
||
|
|
||
|
(** Simple check for dead code. *)
|
||
|
|
||
|
let verbose = false
|
||
|
|
||
|
module State = struct
|
||
|
type t =
|
||
|
{
|
||
|
visited : Cfg.NodeSet.t;
|
||
|
}
|
||
|
|
||
|
let initial =
|
||
|
{
|
||
|
visited = Cfg.NodeSet.empty;
|
||
|
}
|
||
|
|
||
|
let equal t1 t2 =
|
||
|
Cfg.NodeSet.equal t1.visited t2.visited
|
||
|
|
||
|
let join t1 t2 =
|
||
|
{
|
||
|
visited = Cfg.NodeSet.union t1.visited t2.visited
|
||
|
}
|
||
|
|
||
|
let add_visited node t =
|
||
|
{
|
||
|
visited = Cfg.NodeSet.add node t.visited;
|
||
|
}
|
||
|
|
||
|
let get_visited t =
|
||
|
t.visited
|
||
|
|
||
|
let pp fmt t =
|
||
|
F.fprintf fmt "visited: %a"
|
||
|
(pp_seq Cfg.Node.pp) (Cfg.NodeSet.elements t.visited)
|
||
|
|
||
|
let num_visited t =
|
||
|
Cfg.NodeSet.cardinal t.visited
|
||
|
end
|
||
|
|
||
|
let do_node node (s : State.t) : (State.t list) * (State.t list) =
|
||
|
let s' = State.add_visited node s in
|
||
|
if verbose then L.stderr " N:%a (#visited: %a)@."
|
||
|
Cfg.Node.pp node
|
||
|
State.pp s';
|
||
|
[s'], [s']
|
||
|
|
||
|
|
||
|
(** Report an error. *)
|
||
|
let report_error description pn pd loc =
|
||
|
if verbose then L.stderr "ERROR: %s@." description;
|
||
|
Checkers.ST.report_error pn pd "CHECKERS_DEAD_CODE" loc description
|
||
|
|
||
|
|
||
|
(** Check the final state at the end of the analysis. *)
|
||
|
let check_final_state proc_name proc_desc exit_node final_s =
|
||
|
let proc_nodes = Cfg.Procdesc.get_nodes proc_desc in
|
||
|
let tot_nodes = list_length proc_nodes in
|
||
|
let tot_visited = State.num_visited final_s in
|
||
|
if verbose then L.stderr "TOT nodes: %d (visited: %n)@." tot_nodes tot_visited;
|
||
|
if tot_nodes <> tot_visited then
|
||
|
begin
|
||
|
let not_visited =
|
||
|
list_filter (fun n -> not (Cfg.NodeSet.mem n (State.get_visited final_s))) proc_nodes in
|
||
|
let do_node n =
|
||
|
let loc = Cfg.Node.get_loc n in
|
||
|
let description = Format.sprintf "Node not visited: %d" (Cfg.Node.get_id n) in
|
||
|
let report = match Cfg.Node.get_kind n with
|
||
|
| Cfg.Node.Join_node -> false
|
||
|
| k when k = Cfg.Node.exn_sink_kind -> false
|
||
|
| _ -> true in
|
||
|
if report
|
||
|
then report_error description proc_name proc_desc loc in
|
||
|
list_iter do_node not_visited
|
||
|
end
|
||
|
|
||
|
(** Simple check for dead code. *)
|
||
|
let callback_check_dead_code
|
||
|
(all_procs : Procname.t list)
|
||
|
(get_proc_desc: Procname.t -> Cfg.Procdesc.t option)
|
||
|
(idenv: Idenv.t)
|
||
|
(tenv: Sil.tenv)
|
||
|
(proc_name: Procname.t)
|
||
|
(proc_desc : Cfg.Procdesc.t) : unit =
|
||
|
|
||
|
let module DFDead = MakeDF(struct
|
||
|
type t = State.t
|
||
|
let equal = State.equal
|
||
|
let join = State.join
|
||
|
let do_node = do_node
|
||
|
let proc_throws pn = DontKnow
|
||
|
end) in
|
||
|
|
||
|
let do_check () =
|
||
|
begin
|
||
|
if verbose then L.stderr "@.--@.PROC: %a@." Procname.pp proc_name;
|
||
|
let transitions = DFDead.run proc_desc State.initial in
|
||
|
let exit_node = Cfg.Procdesc.get_exit_node proc_desc in
|
||
|
match transitions exit_node with
|
||
|
| DFDead.Transition (pre_final_s, _, _) ->
|
||
|
let final_s = State.add_visited exit_node pre_final_s in
|
||
|
check_final_state proc_name proc_desc exit_node final_s
|
||
|
| DFDead.Dead_state -> ()
|
||
|
end in
|
||
|
|
||
|
do_check ()
|