[clang] Added logging of caught exceptions of type IncorrectAssumption to clang frontend

Summary:
- During program translation, infer logs details about IncorrectAssumption exceptions that are caught
- Logging is integrated with EventLogger library, uses existing FrontendException event type
- IncorrectAssumption exception type extended to add support for storing exception details
	- All instances where IncorrectAssumption exception is raised modified to pass these details

Reviewed By: mbouaziz

Differential Revision: D6759287

fbshipit-source-id: 64f520e
master
Varun Arora 7 years ago committed by Facebook Github Bot
parent 0ff4a1a3f0
commit 773b43d94e

@ -178,7 +178,8 @@ let make_next_object_exp stmt_info item items =
let decl_ref_expr_info = make_decl_ref_expr_info decl_ref in
(Clang_ast_t.DeclRefExpr (stmt_info_var, [], expr_info, decl_ref_expr_info), var_qual_type)
| _ ->
CFrontend_config.incorrect_assumption "unexpected item %a"
CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None
"unexpected item %a"
(Pp.to_string ~f:Clang_ast_j.string_of_stmt)
item
in

@ -20,15 +20,22 @@ let string_of_clang_lang (lang: clang_lang) : string =
let equal_clang_lang = [%compare.equal : clang_lang]
exception IncorrectAssumption of string
type exception_details =
{ msg: string
; position: string * int * int * int
; source_range: Clang_ast_t.source_range
; ast_node: string option }
let incorrect_assumption fmt = F.kasprintf (fun msg -> raise (IncorrectAssumption msg)) fmt
exception Unimplemented of exception_details
exception Unimplemented of
string * (string * int * int * int) * Clang_ast_t.source_range * string option
let unimplemented position source_range ast_node fmt =
F.kasprintf (fun msg -> raise (Unimplemented {msg; position; source_range; ast_node})) fmt
let unimplemented pos source_range ast_node fmt =
F.kasprintf (fun msg -> raise (Unimplemented (msg, pos, source_range, ast_node))) fmt
exception IncorrectAssumption of exception_details
let incorrect_assumption position source_range ast_node fmt =
F.kasprintf (fun msg -> raise (IncorrectAssumption {msg; position; source_range; ast_node})) fmt
type translation_unit_context = {lang: clang_lang; source_file: SourceFile.t}

@ -17,14 +17,13 @@ val string_of_clang_lang : clang_lang -> string
val equal_clang_lang : clang_lang -> clang_lang -> bool
exception IncorrectAssumption of string
type exception_details =
{ msg: string
; position: string * int * int * int
; source_range: Clang_ast_t.source_range
; ast_node: string option }
val incorrect_assumption : ('a, Format.formatter, unit, _) format4 -> 'a
(** Used to mark places in the frontend that incorrectly assume something to be
impossible. TODO(t21762295) get rid of all instances of this. *)
exception Unimplemented of
string * (string * int * int * int) * Clang_ast_t.source_range * string option
exception Unimplemented of exception_details
val unimplemented :
string * int * int * int -> Clang_ast_t.source_range -> string option
@ -32,6 +31,14 @@ val unimplemented :
(** Raise Unimplemented. This is caught at the level of translating a method and makes the frontend
give up on that method. *)
exception IncorrectAssumption of exception_details
val incorrect_assumption :
string * int * int * int -> Clang_ast_t.source_range -> string option
-> ('a, Format.formatter, unit, _) format4 -> 'a
(** Used to mark places in the frontend that incorrectly assume something to be
impossible. TODO(t21762295) get rid of all instances of this. *)
type translation_unit_context = {lang: clang_lang; source_file: SourceFile.t}
(** Constants *)

@ -35,15 +35,19 @@ let protect ~f ~recover ~pp_context (trans_unit_ctx: CFrontend_config.translatio
(* Always keep going in case of known limitations of the frontend, crash otherwise (by not
catching the exception) unless `--keep-going` was passed. Print errors we should fix
(t21762295) to the console. *)
| CFrontend_config.Unimplemented (msg, exception_pos, source_range, ast_node) ->
| CFrontend_config.Unimplemented e ->
let caught_unimplemented_exception =
caught_exception "Unimplemented" exception_pos source_range ast_node
caught_exception "Unimplemented" e.position e.source_range e.ast_node
in
EventLogger.log caught_unimplemented_exception ;
log_and_recover ~print:false "Unimplemented feature:@\n %s@\n" msg
| CFrontend_config.IncorrectAssumption msg ->
log_and_recover ~print:false "Unimplemented feature:@\n %s@\n" e.msg
| CFrontend_config.IncorrectAssumption e ->
(* FIXME(t21762295): we do not expect this to happen but it does *)
log_and_recover ~print:true "Known incorrect assumption in the frontend: %s@\n" msg
let caught_incorrect_assumption =
caught_exception "IncorrectAssumption" e.position e.source_range e.ast_node
in
EventLogger.log caught_incorrect_assumption ;
log_and_recover ~print:true "Known incorrect assumption in the frontend: %s@\n" e.msg
| CTrans_utils.Self.SelfClassException class_name ->
(* FIXME(t21762295): we do not expect this to happen but it does *)
log_and_recover ~print:true "Unexpected SelfClassException %a@\n" Typ.Name.pp class_name
@ -339,7 +343,7 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
(* create the corresponding global variable to get the right pname for its
initializer *)
let global =
CGeneral_utils.mk_sil_global_var trans_unit_ctx named_decl_info vdi qt
CGeneral_utils.mk_sil_global_var trans_unit_ctx decl_info named_decl_info vdi qt
in
(* safe to Option.get because it's a global *)
Option.value_exn (Pvar.get_initializer_pname global)

@ -79,7 +79,7 @@ let is_objc_extension translation_unit_context =
|| CFrontend_config.equal_clang_lang lang CFrontend_config.ObjCPP
let get_var_name_mangled name_info var_decl_info =
let get_var_name_mangled decl_info name_info var_decl_info =
let clang_name = CAst_utils.get_qualified_name name_info |> QualifiedCppName.to_qual_string in
let param_idx_opt = var_decl_info.Clang_ast_t.vdi_parm_index_in_function in
let name_string =
@ -87,7 +87,7 @@ let get_var_name_mangled name_info var_decl_info =
| "", Some index ->
"__param_" ^ string_of_int index
| "", None ->
CFrontend_config.incorrect_assumption
CFrontend_config.incorrect_assumption __POS__ decl_info.Clang_ast_t.di_source_range None
"Got both empty clang_name and None for param_idx in get_var_name_mangled (%a) (%a)"
(Pp.to_string ~f:Clang_ast_j.string_of_named_decl_info)
name_info
@ -106,9 +106,9 @@ let get_var_name_mangled name_info var_decl_info =
(name_string, mangled)
let mk_sil_global_var {CFrontend_config.source_file} ?(mk_name= fun _ x -> x) named_decl_info
var_decl_info qt =
let name_string, simple_name = get_var_name_mangled named_decl_info var_decl_info in
let mk_sil_global_var {CFrontend_config.source_file} ?(mk_name= fun _ x -> x) decl_info
named_decl_info var_decl_info qt =
let name_string, simple_name = get_var_name_mangled decl_info named_decl_info var_decl_info in
let translation_unit =
match Clang_ast_t.(var_decl_info.vdi_is_extern, var_decl_info.vdi_init_expr) with
| true, None ->
@ -150,7 +150,9 @@ let mk_sil_global_var {CFrontend_config.source_file} ?(mk_name= fun _ x -> x) na
let mk_sil_var trans_unit_ctx named_decl_info decl_info_qual_type_opt procname outer_procname =
match decl_info_qual_type_opt with
| Some (decl_info, qt, var_decl_info, should_be_mangled) ->
let name_string, simple_name = get_var_name_mangled named_decl_info var_decl_info in
let name_string, simple_name =
get_var_name_mangled decl_info named_decl_info var_decl_info
in
if var_decl_info.Clang_ast_t.vdi_is_global then
let mk_name =
if var_decl_info.Clang_ast_t.vdi_is_static_local then
@ -159,7 +161,7 @@ let mk_sil_var trans_unit_ctx named_decl_info decl_info_qual_type_opt procname o
Mangled.from_string (Typ.Procname.to_string outer_procname ^ "_" ^ name_string) )
else None
in
mk_sil_global_var trans_unit_ctx ?mk_name named_decl_info var_decl_info qt
mk_sil_global_var trans_unit_ctx ?mk_name decl_info named_decl_info var_decl_info qt
else if not should_be_mangled then Pvar.mk simple_name procname
else
let start_location = fst decl_info.Clang_ast_t.di_source_range in

@ -24,11 +24,13 @@ val list_range : int -> int -> int list
val mk_class_field_name : Typ.Name.t -> string -> Typ.Fieldname.t
val get_var_name_mangled :
Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info -> string * Mangled.t
Clang_ast_t.decl_info -> Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info
-> string * Mangled.t
val mk_sil_global_var :
CFrontend_config.translation_unit_context -> ?mk_name:(string -> Mangled.t -> Mangled.t)
-> Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info -> Clang_ast_t.qual_type -> Pvar.t
-> Clang_ast_t.decl_info -> Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info
-> Clang_ast_t.qual_type -> Pvar.t
val mk_sil_var :
CFrontend_config.translation_unit_context -> Clang_ast_t.named_decl_info -> var_info option

@ -126,11 +126,11 @@ let is_cpp_nothrow function_method_decl_info =
1. self/this parameter (optional, only for methods)
2. normal parameters
3. return parameter (optional) *)
let get_parameters trans_unit_ctx tenv function_method_decl_info =
let get_parameters trans_unit_ctx tenv decl_info function_method_decl_info =
let par_to_ms_par par =
match par with
| Clang_ast_t.ParmVarDecl (_, name_info, qt, var_decl_info) ->
let _, mangled = CGeneral_utils.get_var_name_mangled name_info var_decl_info in
let _, mangled = CGeneral_utils.get_var_name_mangled decl_info name_info var_decl_info in
let param_typ = CType_decl.qual_type_to_sil_type tenv qt in
let new_qt =
match param_typ.Typ.desc with
@ -163,7 +163,7 @@ let build_method_signature trans_unit_ctx tenv decl_info procname function_metho
let source_range = decl_info.Clang_ast_t.di_source_range in
let tp, return_param_type_opt = get_return_val_and_param_types tenv function_method_decl_info in
let is_instance_method = is_instance_method function_method_decl_info in
let parameters = get_parameters trans_unit_ctx tenv function_method_decl_info in
let parameters = get_parameters trans_unit_ctx tenv decl_info function_method_decl_info in
let attributes = decl_info.Clang_ast_t.di_attributes in
let lang = get_language trans_unit_ctx function_method_decl_info in
let is_cpp_virtual = is_cpp_virtual function_method_decl_info in

@ -516,7 +516,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
assert false )
| _ as decl ->
(* FIXME(t21762295): we do not expect this to happen but it does *)
CFrontend_config.incorrect_assumption
CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None
"di_parent_pointer should be always set for fields/ivars, but got %a"
(Pp.option (Pp.to_string ~f:Clang_ast_j.string_of_decl))
decl
@ -709,7 +709,9 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
in
let procname = Procdesc.get_proc_name context.procdesc in
let sil_loc = CLocation.get_sil_location stmt_info context in
let pvar = CVar_decl.sil_var_of_decl_ref context decl_ref procname in
let pvar =
CVar_decl.sil_var_of_decl_ref context stmt_info.Clang_ast_t.si_source_range decl_ref procname
in
CContext.add_block_static_var context procname (pvar, typ) ;
let var_exp = Exp.Lvar pvar in
let exps =
@ -986,7 +988,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
if Int.equal (List.length params) (List.length params_stmt) then params
else
(* FIXME(t21762295) this is reachable *)
CFrontend_config.incorrect_assumption
CFrontend_config.incorrect_assumption __POS__ si.Clang_ast_t.si_source_range None
"In call to %a: stmt_list and res_trans_par.exps must have same size but they don't:@\nstmt_list(%d)=[%a]@\nres_trans_par.exps(%d)=[%a]@\n"
Typ.Procname.pp procname (List.length params) (Pp.seq Exp.pp)
(List.map ~f:fst params) (List.length params_stmt)
@ -1024,8 +1026,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
pn
| _ ->
(* method pointer not implemented, this shouldn't happen but it does (t21762295) *)
CFrontend_config.incorrect_assumption "Could not resolve CXX method call %a" Exp.pp
sil_method
CFrontend_config.incorrect_assumption __POS__ si.Clang_ast_t.si_source_range None
"Could not resolve CXX method call %a" Exp.pp sil_method
in
(* As we may have nodes coming from different parameters we need to call instruction for each
parameter and collect the results afterwards. The 'instructions' function does not do that *)
@ -1852,7 +1854,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
{empty_res_trans with root_nodes= top_nodes; leaf_nodes= succ_nodes}
| _ ->
(* TODO(t21762295) this raises sometimes *)
CFrontend_config.incorrect_assumption
CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None
"Unexpected Switch Statement sub-expression list: [%a]"
(Pp.semicolon_seq (Pp.to_string ~f:Clang_ast_j.string_of_stmt))
switch_stmt_list
@ -2237,7 +2239,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
(* Record declaration is done in the beginning when procdesc is defined.*)
collect_all_decl trans_state var_decls' next_nodes stmt_info
| decl :: _ ->
CFrontend_config.incorrect_assumption "unexpected decl type %s in collect_all_decl: %a"
CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None
"unexpected decl type %s in collect_all_decl: %a"
(Clang_ast_proj.get_decl_kind_string decl)
(Pp.to_string ~f:Clang_ast_j.string_of_decl)
decl
@ -2603,7 +2606,10 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
(* defining procedure. We add an edge in the call graph.*)
Cg.add_edge context.cg procname block_pname ;
let captured_block_vars = block_decl_info.Clang_ast_t.bdi_captured_variables in
let captureds = CVar_decl.captured_vars_from_block_info context captured_block_vars in
let captureds =
CVar_decl.captured_vars_from_block_info context stmt_info.Clang_ast_t.si_source_range
captured_block_vars
in
let ids_instrs = List.map ~f:assign_captured_var captureds in
let ids, instrs = List.unzip ids_instrs in
let block_data = (context, qual_type, block_pname, captureds) in
@ -2631,7 +2637,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
Cg.add_edge context.cg procname lambda_pname ;
let make_captured_tuple (pvar, typ) = (Exp.Lvar pvar, pvar, typ) in
let get_captured_pvar_typ decl_ref =
CVar_decl.sil_var_of_captured_var decl_ref context procname
CVar_decl.sil_var_of_captured_var decl_ref context stmt_info.Clang_ast_t.si_source_range
procname
in
let translate_capture_init (pvar, typ) init_decl =
match init_decl with
@ -2983,7 +2990,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
if destr_trans_result.root_nodes <> [] then destr_trans_result
else {empty_res_trans with root_nodes= bn.break}
| _ (* t21762295 *) ->
CFrontend_config.incorrect_assumption "Break stmt without continuation: %a"
CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None
"Break stmt without continuation: %a"
(Pp.to_string ~f:Clang_ast_j.string_of_stmt_info)
stmt_info
@ -2996,7 +3004,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
if destr_trans_result.root_nodes <> [] then destr_trans_result
else {empty_res_trans with root_nodes= bn.continue}
| _ (* t21762295 *) ->
CFrontend_config.incorrect_assumption "Continue stmt without continuation: %a"
CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None
"Continue stmt without continuation: %a"
(Pp.to_string ~f:Clang_ast_j.string_of_stmt_info)
stmt_info
@ -3052,7 +3061,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
switchStmt_trans trans_state stmt_info switch_stmt_list
| CaseStmt _ ->
(* where do we even get case stmts outside of the switch stmt? (t21762295) *)
CFrontend_config.incorrect_assumption "Case statement outside of switch statement: %a"
CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None
"Case statement outside of switch statement: %a"
(Pp.to_string ~f:Clang_ast_j.string_of_stmt)
instr
| StmtExpr (_, stmt_list, _) ->
@ -3240,7 +3250,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
(Pp.to_string ~f:Clang_ast_j.string_of_stmt)
instr
| ForStmt (_, _) | WhileStmt (_, _) | DoStmt (_, _) | ObjCForCollectionStmt (_, _) ->
CFrontend_config.incorrect_assumption "Unexpected shape for %a: %a"
CFrontend_config.incorrect_assumption __POS__ stmt_info.Clang_ast_t.si_source_range None
"Unexpected shape for %a: %a"
(Pp.to_string ~f:Clang_ast_proj.get_stmt_kind_string)
instr
(Pp.to_string ~f:Clang_ast_j.string_of_stmt)

@ -34,7 +34,7 @@ let sil_var_of_decl context var_decl procname =
assert false
let sil_var_of_decl_ref context decl_ref procname =
let sil_var_of_decl_ref context source_range decl_ref procname =
let name =
match decl_ref.Clang_ast_t.dr_name with Some name_info -> name_info | None -> assert false
in
@ -53,7 +53,7 @@ let sil_var_of_decl_ref context decl_ref procname =
sil_var_of_decl context var_decl procname
| None ->
(* FIXME(t21762295) *)
CFrontend_config.incorrect_assumption
CFrontend_config.incorrect_assumption __POS__ source_range None
"pointer '%d' for var decl not found. The var decl was: %a" pointer
(Pp.to_string ~f:Clang_ast_j.string_of_decl_ref)
decl_ref
@ -80,24 +80,24 @@ let add_var_to_locals procdesc var_decl typ pvar =
assert false
let sil_var_of_captured_var decl_ref context procname =
let sil_var_of_captured_var decl_ref context source_range procname =
match decl_ref with
| {Clang_ast_t.dr_qual_type= Some qual_type} ->
( sil_var_of_decl_ref context decl_ref procname
( sil_var_of_decl_ref context source_range decl_ref procname
, CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type )
| _ ->
assert false
(* Returns a list of captured variables as sil variables. *)
let captured_vars_from_block_info context cvl =
let captured_vars_from_block_info context source_range cvl =
let procname = Procdesc.get_proc_name context.CContext.procdesc in
let sil_var_of_captured_var {Clang_ast_t.bcv_variable} vars_acc =
match bcv_variable with
| Some ({Clang_ast_t.dr_name= Some {Clang_ast_t.ni_name}} as decl_ref) ->
if String.equal ni_name CFrontend_config.self && not (CContext.is_objc_instance context)
then vars_acc
else sil_var_of_captured_var decl_ref context procname :: vars_acc
else sil_var_of_captured_var decl_ref context source_range procname :: vars_acc
| _ ->
assert false
in

@ -15,12 +15,15 @@ open! IStd
val sil_var_of_decl : CContext.t -> Clang_ast_t.decl -> Typ.Procname.t -> Pvar.t
val sil_var_of_decl_ref : CContext.t -> Clang_ast_t.decl_ref -> Typ.Procname.t -> Pvar.t
val sil_var_of_decl_ref :
CContext.t -> Clang_ast_t.source_range -> Clang_ast_t.decl_ref -> Typ.Procname.t -> Pvar.t
val add_var_to_locals : Procdesc.t -> Clang_ast_t.decl -> Typ.t -> Pvar.t -> unit
val sil_var_of_captured_var :
Clang_ast_t.decl_ref -> CContext.t -> Typ.Procname.t -> Pvar.t * Typ.typ
Clang_ast_t.decl_ref -> CContext.t -> Clang_ast_t.source_range -> Typ.Procname.t
-> Pvar.t * Typ.typ
val captured_vars_from_block_info :
CContext.t -> Clang_ast_t.block_captured_variable list -> (Pvar.t * Typ.t) list
CContext.t -> Clang_ast_t.source_range -> Clang_ast_t.block_captured_variable list
-> (Pvar.t * Typ.t) list

Loading…
Cancel
Save