[cfg] Log if the cfg is broken for a join node or not

Reviewed By: dulmarod

Differential Revision: D7985793

fbshipit-source-id: 4010954
master
Daiva Naudziuniene 7 years ago committed by Facebook Github Bot
parent d70d23c5f3
commit 4e821129a4

@ -53,7 +53,7 @@ let iter_all_nodes ?(sorted= false) cfg ~f =
|> List.iter ~f:(fun (_, d, n) -> f d n)
let is_proc_cfg_connected proc_desc =
let proc_cfg_broken_for_node proc_desc =
let is_exit_node n =
match Procdesc.Node.get_kind n with Procdesc.Node.Exit_node _ -> true | _ -> false
in
@ -79,26 +79,43 @@ let is_proc_cfg_connected proc_desc =
| _ ->
is_between_join_and_exit_node n
in
let is_broken_node n =
let find_broken_node n =
let succs = Procdesc.Node.get_succs n in
let preds = Procdesc.Node.get_preds n in
match Procdesc.Node.get_kind n with
| Procdesc.Node.Start_node _ ->
List.is_empty succs || not (List.is_empty preds)
if List.is_empty succs || not (List.is_empty preds) then Some `Other else None
| Procdesc.Node.Exit_node _ ->
not (List.is_empty succs) || List.is_empty preds
if not (List.is_empty succs) || List.is_empty preds then Some `Other else None
| Procdesc.Node.Stmt_node _ | Procdesc.Node.Prune_node _ | Procdesc.Node.Skip_node _ ->
List.is_empty succs || List.is_empty preds
if List.is_empty succs || List.is_empty preds then Some `Other else None
| Procdesc.Node.Join_node ->
(* Join node has the exception that it may be without predecessors
and pointing to between_join_and_exit which points to an exit node.
This happens when the if branches end with a return.
Nested if statements, where all branches have return statements,
introduce a sequence of join nodes *)
(List.is_empty preds && not (is_consecutive_join_nodes n Procdesc.NodeSet.empty))
|| (not (List.is_empty preds) && List.is_empty succs)
if
(List.is_empty preds && not (is_consecutive_join_nodes n Procdesc.NodeSet.empty))
|| (not (List.is_empty preds) && List.is_empty succs)
then Some `Join
else None
in
not (List.exists ~f:is_broken_node (Procdesc.get_nodes proc_desc))
let rec find_first_broken nodes res_broken_node =
match nodes with
| [] ->
res_broken_node
| n :: nodes' ->
let broken_node = find_broken_node n in
match broken_node with
| None ->
find_first_broken nodes' res_broken_node
| Some `Join ->
find_first_broken nodes' broken_node
| Some `Other ->
broken_node
in
find_first_broken (Procdesc.get_nodes proc_desc) None
let load_statement =

@ -32,7 +32,7 @@ val create_proc_desc : t -> ProcAttributes.t -> Procdesc.t
val iter_all_nodes : ?sorted:bool -> t -> f:(Procdesc.t -> Procdesc.Node.t -> unit) -> unit
(** Iterate over all the nodes in the cfg *)
val is_proc_cfg_connected : Procdesc.t -> bool
val proc_cfg_broken_for_node : Procdesc.t -> [`Join | `Other] option
(** checks whether a cfg for the given procdesc is connected or not *)
val save_attributes : SourceFile.t -> t -> unit

@ -22,15 +22,18 @@ let log_caught_exception (trans_unit_ctx: CFrontend_config.translation_unit_cont
EventLogger.log caught_exception
let log_broken_cfg procdesc exception_triggered_location ~lang =
let log_broken_cfg ~broken_node procdesc exception_triggered_location ~lang =
let proc_location = Procdesc.get_loc procdesc in
let exception_type =
match broken_node with `Other -> "Broken CFG" | `Join -> "Broken CFG at join node"
in
let cfg_exception =
EventLogger.FrontendException
{ source_location_start= proc_location
; source_location_end= proc_location
; ast_node= None
; exception_triggered_location
; exception_type= "Broken CFG"
; exception_type
; lang }
in
EventLogger.log cfg_exception

@ -13,4 +13,5 @@ val log_caught_exception :
CFrontend_config.translation_unit_context -> string -> Logging.ocaml_pos
-> Clang_ast_t.source_location * Clang_ast_t.source_location -> string option -> unit
val log_broken_cfg : Procdesc.t -> Logging.ocaml_pos -> lang:string -> unit
val log_broken_cfg :
broken_node:[`Join | `Other] -> Procdesc.t -> Logging.ocaml_pos -> lang:string -> unit

@ -62,7 +62,8 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
in
let f () =
match Typ.Procname.Hash.find cfg procname with
| procdesc when Procdesc.is_defined procdesc && not (model_exists procname) ->
| procdesc when Procdesc.is_defined procdesc && not (model_exists procname)
-> (
let vars_to_destroy = CTrans_utils.Scope.compute_vars_to_destroy body in
let context =
CContext.create_context trans_unit_ctx tenv cfg procdesc class_decl_opt
@ -80,11 +81,14 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
Procdesc.Node.add_locals_ret_declaration start_node proc_attributes
(Procdesc.get_locals procdesc) ;
Procdesc.node_set_succs_exn procdesc start_node meth_body_nodes [] ;
if not (Cfg.is_proc_cfg_connected procdesc) then
let lang =
CFrontend_config.string_of_clang_lang trans_unit_ctx.CFrontend_config.lang
in
ClangLogging.log_broken_cfg procdesc __POS__ ~lang
match Cfg.proc_cfg_broken_for_node procdesc with
| None ->
()
| Some broken_node ->
let lang =
CFrontend_config.string_of_clang_lang trans_unit_ctx.CFrontend_config.lang
in
ClangLogging.log_broken_cfg ~broken_node procdesc __POS__ ~lang )
| _ ->
()
| exception Caml.Not_found ->

Loading…
Cancel
Save