From 2fff3b0733e473faef2a6179ab6ae2f49997e9b0 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Thu, 14 Sep 2017 03:12:09 -0700 Subject: [PATCH] [clang] distinguish genuine internal failures from unimplemented features Summary: The clang frontend uses `assert false` for unimplemented features that should abort method translations, as well as for genuine internal errors. Distinguishing between the two, we can fail hard on the latter and not the former. 1. This introduces a new exception `Unimplemented` that is used instead of `assert false` where appropriate. 2. Changed some other cases into `die ...` (when there's an error message to display) 3. Wherever a path in the code that we assumed to be unreachable was observed reachable, we now raise `IncorrectAssumption`. These should be fixed, but the fixes are not obvious. Reviewed By: sblackshear Differential Revision: D5784384 fbshipit-source-id: 61b55af --- infer/src/base/Pp.ml | 2 + infer/src/base/Pp.mli | 2 + infer/src/clang/Capture.ml | 16 +- infer/src/clang/ast_expressions.ml | 8 +- infer/src/clang/cFrontend_checkers_main.ml | 60 +++--- infer/src/clang/cFrontend_config.ml | 9 + infer/src/clang/cFrontend_config.mli | 12 ++ infer/src/clang/cFrontend_decl.ml | 41 +++-- infer/src/clang/cFrontend_errors.ml | 9 +- infer/src/clang/cMethod_trans.ml | 12 +- infer/src/clang/cTL.ml | 5 +- infer/src/clang/cTrans.ml | 204 +++++++++++++++++---- infer/src/clang/cTrans_utils.ml | 9 +- infer/src/clang/cTrans_utils.mli | 4 - infer/src/eradicate/AnnotatedSignature.ml | 8 +- infer/src/eradicate/models.ml | 4 +- infer/src/harness/inhabit.ml | 3 +- 17 files changed, 263 insertions(+), 145 deletions(-) diff --git a/infer/src/base/Pp.ml b/infer/src/base/Pp.ml index a5418f6b6..9f0a18ac9 100644 --- a/infer/src/base/Pp.ml +++ b/infer/src/base/Pp.ml @@ -138,6 +138,8 @@ let elapsed_time fmt () = let string fmt s = F.fprintf fmt "%s" s +let option pp fmt = function None -> string fmt "None" | Some x -> F.fprintf fmt "Some %a" pp x + let to_string ~f fmt x = string fmt (f x) let pp_argfile fmt fname = diff --git a/infer/src/base/Pp.mli b/infer/src/base/Pp.mli index 74be752b5..ea3c94e0d 100644 --- a/infer/src/base/Pp.mli +++ b/infer/src/base/Pp.mli @@ -68,6 +68,8 @@ val latex : color -> env val color_string : color -> string (** string representation of colors *) +val option : (F.formatter -> 'a -> unit) -> F.formatter -> 'a option -> unit + val string : F.formatter -> string -> unit val cli_args : F.formatter -> string list -> unit diff --git a/infer/src/clang/Capture.ml b/infer/src/clang/Capture.ml index bf3887b05..6ce955dc0 100644 --- a/infer/src/clang/Capture.ml +++ b/infer/src/clang/Capture.ml @@ -15,25 +15,13 @@ let debug_mode = Config.debug_mode || Config.frontend_stats let buffer_len = 262143 -let catch_biniou_buffer_errors f x = - try[@warning "-52"] f x - with - | Invalid_argument - (* suppress warning: allow this one case because we're just reraising the error with another - error message so it doesn't really matter if this eventually fails *) - "Bi_inbuf.refill_from_channel" - -> - L.external_error "WARNING: biniou buffer too short, skipping the file@\n" ; - assert false - (* This function reads the json file in fname, validates it, and encoded in the AST data structure defined in Clang_ast_t. *) let validate_decl_from_file fname = - catch_biniou_buffer_errors (Ag_util.Biniou.from_file ~len:buffer_len Clang_ast_b.read_decl) fname + Ag_util.Biniou.from_file ~len:buffer_len Clang_ast_b.read_decl fname let validate_decl_from_channel chan = - catch_biniou_buffer_errors (Ag_util.Biniou.from_channel ~len:buffer_len Clang_ast_b.read_decl) - chan + Ag_util.Biniou.from_channel ~len:buffer_len Clang_ast_b.read_decl chan let register_perf_stats_report source_file = let stats_dir = Filename.concat Config.results_dir Config.frontend_stats_dir_name in diff --git a/infer/src/clang/ast_expressions.ml b/infer/src/clang/ast_expressions.ml index cca7d8f38..56c1595cc 100644 --- a/infer/src/clang/ast_expressions.ml +++ b/infer/src/clang/ast_expressions.ml @@ -229,7 +229,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) | _ - -> assert false + -> CFrontend_config.incorrect_assumption "unexpected item %a" + (Pp.to_string ~f:Clang_ast_j.string_of_stmt) item in let message_call = make_message_expr create_id_type CFrontend_config.next_object items stmt_info false @@ -582,7 +583,10 @@ let translate_block_enumerate block_name stmt_info stmt_list ei = ; free_stop ] , op ) | _ - -> assert false + -> (* FIXME(t21762295) this is reachable *) + CFrontend_config.incorrect_assumption "wrong params in block enumerate translation: %a" + (Pp.seq (Pp.to_string ~f:Clang_ast_j.string_of_decl)) + params in let open Clang_ast_t in match stmt_list with diff --git a/infer/src/clang/cFrontend_checkers_main.ml b/infer/src/clang/cFrontend_checkers_main.ml index e29e17463..5564f9108 100644 --- a/infer/src/clang/cFrontend_checkers_main.ml +++ b/infer/src/clang/cFrontend_checkers_main.ml @@ -301,36 +301,32 @@ let do_frontend_checks (trans_unit_ctx: CFrontend_config.translation_unit_contex "Loading the following linters files: %a@\n" (Pp.comma_seq Format.pp_print_string) linters_files ; CTL.create_ctl_evaluation_tracker trans_unit_ctx.source_file ; - try - let parsed_linters = parse_ctl_files linters_files in - let filtered_parsed_linters = - CFrontend_errors.filter_parsed_linters parsed_linters trans_unit_ctx.source_file - in - CFrontend_errors.parsed_linters := filtered_parsed_linters ; - let source_file = trans_unit_ctx.CFrontend_config.source_file in - L.(debug Linters Medium) - "Start linting file %a with rules: @\n%a@\n" SourceFile.pp source_file + let parsed_linters = parse_ctl_files linters_files in + let filtered_parsed_linters = + CFrontend_errors.filter_parsed_linters parsed_linters trans_unit_ctx.source_file + in + CFrontend_errors.parsed_linters := filtered_parsed_linters ; + let source_file = trans_unit_ctx.CFrontend_config.source_file in + L.(debug Linters Medium) + "Start linting file %a with rules: @\n%a@\n" SourceFile.pp source_file + CFrontend_errors.pp_linters filtered_parsed_linters ; + if Config.print_active_checkers then + L.progress "Linting file %a, active linters: @\n%a@\n" SourceFile.pp source_file CFrontend_errors.pp_linters filtered_parsed_linters ; - if Config.print_active_checkers then - L.progress "Linting file %a, active linters: @\n%a@\n" SourceFile.pp source_file - CFrontend_errors.pp_linters filtered_parsed_linters ; - match ast with - | Clang_ast_t.TranslationUnitDecl (_, decl_list, _, _) - -> let context = context_with_ck_set (CLintersContext.empty trans_unit_ctx) decl_list in - let is_decl_allowed decl = - let decl_info = Clang_ast_proj.get_decl_tuple decl in - CLocation.should_do_frontend_check trans_unit_ctx decl_info.Clang_ast_t.di_source_range - in - let allowed_decls = List.filter ~f:is_decl_allowed decl_list in - (* We analyze the top level and then all the allowed declarations *) - CFrontend_errors.invoke_set_of_checkers_on_node context (Ctl_parser_types.Decl ast) ; - List.iter ~f:(do_frontend_checks_decl context) allowed_decls ; - if LintIssues.exists_issues () then store_issues source_file ; - L.(debug Linters Medium) "End linting file %a@\n" SourceFile.pp source_file ; - CTL.save_dotty_when_in_debug_mode trans_unit_ctx.CFrontend_config.source_file - | _ - -> assert false - (* NOTE: Assumes that an AST always starts with a TranslationUnitDecl *) - with Assert_failure (file, line, column) as exn -> - L.internal_error "Fatal error: exception Assert_failure(%s, %d, %d)@\n%!" file line column ; - reraise exn + match ast with + | Clang_ast_t.TranslationUnitDecl (_, decl_list, _, _) + -> let context = context_with_ck_set (CLintersContext.empty trans_unit_ctx) decl_list in + let is_decl_allowed decl = + let decl_info = Clang_ast_proj.get_decl_tuple decl in + CLocation.should_do_frontend_check trans_unit_ctx decl_info.Clang_ast_t.di_source_range + in + let allowed_decls = List.filter ~f:is_decl_allowed decl_list in + (* We analyze the top level and then all the allowed declarations *) + CFrontend_errors.invoke_set_of_checkers_on_node context (Ctl_parser_types.Decl ast) ; + List.iter ~f:(do_frontend_checks_decl context) allowed_decls ; + if LintIssues.exists_issues () then store_issues source_file ; + L.(debug Linters Medium) "End linting file %a@\n" SourceFile.pp source_file ; + CTL.save_dotty_when_in_debug_mode trans_unit_ctx.CFrontend_config.source_file + | _ + -> (* NOTE: Assumes that an AST always starts with a TranslationUnitDecl *) + assert false diff --git a/infer/src/clang/cFrontend_config.ml b/infer/src/clang/cFrontend_config.ml index 3a1967704..51e1fadf1 100644 --- a/infer/src/clang/cFrontend_config.ml +++ b/infer/src/clang/cFrontend_config.ml @@ -8,9 +8,18 @@ *) open! IStd +module F = Format (** Module that contains constants and global state used in the frontend *) +exception IncorrectAssumption of string + +let incorrect_assumption fmt = F.kasprintf (fun msg -> raise (IncorrectAssumption msg)) fmt + +exception Unimplemented of string + +let unimplemented fmt = F.kasprintf (fun msg -> raise (Unimplemented msg)) fmt + type clang_lang = C | CPP | ObjC | ObjCPP [@@deriving compare] let equal_clang_lang = [%compare.equal : clang_lang] diff --git a/infer/src/clang/cFrontend_config.mli b/infer/src/clang/cFrontend_config.mli index 6344850e1..9df41ee3f 100644 --- a/infer/src/clang/cFrontend_config.mli +++ b/infer/src/clang/cFrontend_config.mli @@ -11,6 +11,18 @@ open! IStd (** Module that contains constants and global state used in the frontend *) +exception IncorrectAssumption of string + +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 + +val unimplemented : ('a, Format.formatter, unit, _) format4 -> 'a +(** Raise Unimplemented. This is caught at the level of translating a method and makes the frontend + give up on that method. *) + type clang_lang = C | CPP | ObjC | ObjCPP [@@deriving compare] val equal_clang_lang : clang_lang -> clang_lang -> bool diff --git a/infer/src/clang/cFrontend_decl.ml b/infer/src/clang/cFrontend_decl.ml index 54a1c9333..bd2900d6b 100644 --- a/infer/src/clang/cFrontend_decl.ml +++ b/infer/src/clang/cFrontend_decl.ml @@ -19,12 +19,14 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron (* Translates the method/function's body into nodes of the cfg. *) let add_method trans_unit_ctx tenv cg cfg class_decl_opt procname body has_return_param is_objc_method outer_context_opt extra_instrs = - let handle_translation_failure () = + L.(debug Capture Verbose) + "@\n@\n>>---------- ADDING METHOD: '%a' ---------<<@\n@\n" Typ.Procname.pp procname ; + let handle_frontend_failure ~print fmt = Cfg.remove_proc_desc cfg procname ; - CMethod_trans.create_external_procdesc cfg procname is_objc_method None + CMethod_trans.create_external_procdesc cfg procname is_objc_method None ; + (if print then L.internal_error else L.(debug Capture Quiet)) + ("Aborting translation of method '%a':@\n" ^^ fmt) Typ.Procname.pp procname in - L.(debug Capture Verbose) - "@\n@\n>>---------- ADDING METHOD: '%s' ---------<<@\n@." (Typ.Procname.to_string procname) ; try match Cfg.find_proc_desc_from_name cfg procname with | Some procdesc @@ -48,22 +50,21 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron | None -> () with - | Not_found - -> () - | CTrans_utils.Self.SelfClassException _ - -> (* this shouldn't happen, because self or [a class] should always be arguments of - functions. This is to make sure I'm not wrong. *) - assert false - | CTrans_utils.TemplatedCodeException _ - -> L.internal_error "Fatal error: frontend doesn't support translation of templated code@\n" ; - handle_translation_failure () - | CTrans_utils.UnsupportedStatementException stmt when Config.keep_going - -> L.internal_error "Unimplemented: translation for statement %s" - (Clang_ast_proj.get_stmt_kind_string stmt) ; - handle_translation_failure () - | Assert_failure (file, line, column) when Config.keep_going - -> L.internal_error "Fatal error: exception Assert_failure(%s, %d, %d)@\n%!" file line column ; - handle_translation_failure () + (* 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 + -> handle_frontend_failure ~print:false "Unimplemented feature:@\n %s@\n" msg + | CFrontend_config.IncorrectAssumption msg + -> (* FIXME(t21762295): we do not expect this to happen but it does *) + handle_frontend_failure ~print:true "Known incorrect assumption in the frontend: %s@\n" msg + | CTrans_utils.Self.SelfClassException class_name + -> (* FIXME(t21762295): we do not expect this to happen but it does *) + handle_frontend_failure ~print:true "Unexpected SelfClassException %a@\n" Typ.Name.pp + class_name + | exn when Config.keep_going + -> handle_frontend_failure ~print:true "Frontend error: %a@\nBacktrace:@\n%s" Exn.pp exn + (Exn.backtrace ()) let function_decl trans_unit_ctx tenv cfg cg func_decl block_data_opt = let captured_vars, outer_context_opt = diff --git a/infer/src/clang/cFrontend_errors.ml b/infer/src/clang/cFrontend_errors.ml index f2b21854a..5a064c9ff 100644 --- a/infer/src/clang/cFrontend_errors.ml +++ b/infer/src/clang/cFrontend_errors.ml @@ -118,8 +118,7 @@ let evaluate_place_holder context ph an = | "%name%" -> MF.monospaced_to_string (Ctl_parser_types.ast_node_name an) | _ - -> L.internal_error "ERROR: helper function %s is unknown. Stop.@\n" ph ; - assert false + -> L.die InternalError "helper function %s is unknown" ph (* given a message this function searches for a place-holder identifier, eg %id%. Then it evaluates id and replaces %id% in message @@ -156,8 +155,7 @@ let string_to_err_kind = function | "LIKE" -> Exceptions.Klike | s - -> L.internal_error "@\n[ERROR] Severity %s does not exist. Stop.@\n" s ; - assert false + -> L.die InternalError "Severity %s does not exist" s let string_to_issue_mode m = match m with @@ -166,8 +164,7 @@ let string_to_issue_mode m = | "OFF" -> CIssue.Off | s - -> L.internal_error "@\n[ERROR] Mode %s does not exist. Please specify ON/OFF@\n" s ; - assert false + -> L.die InternalError "Mode %s does not exist. Please specify ON/OFF" s let post_process_linter_definition (linter: linter) = match diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index 2dd1261b9..8ec3dabd5 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -656,19 +656,13 @@ let get_procname_from_cpp_lambda context dec = -> let name_info, decl_ptr, _ = CAst_utils.get_info_from_decl_ref dr in create_procdesc_with_pointer context decl_ptr None name_info.ni_name | _ - -> (* We should not get here *) assert false ) + -> assert false ) | _ - -> (* We should not get here *) assert false + -> assert false let get_captures_from_cpp_lambda dec = match dec with | Clang_ast_t.CXXRecordDecl (_, _, _, _, _, _, _, cxx_rdi) -> cxx_rdi.xrdi_lambda_captures | _ - -> (* We should not get here *) assert false - -(* -let instance_to_method_call_type instance = - if instance then MCVirtual - else MCStatic -*) + -> assert false diff --git a/infer/src/clang/cTL.ml b/infer/src/clang/cTL.ml index 58675765e..70948dce9 100644 --- a/infer/src/clang/cTL.ml +++ b/infer/src/clang/cTL.ml @@ -59,7 +59,6 @@ type t = | EH of ALVar.alexp list * t | ET of ALVar.alexp list * transitions option * t - let has_transition phi = match phi with | True @@ -609,7 +608,9 @@ let transition_decl_to_stmt d trs = | InitExpr, CXXConstructorDecl _ | InitExpr, CXXConversionDecl _ | InitExpr, CXXDestructorDecl _ - -> assert false (* to be done. Requires extending to lists *) + -> (* requires extending to lists *) + CFrontend_config.unimplemented + "transition_decl_to_stmt: InitExpr/CXX{Method,Constructor,Conversion,Destructor}" | InitExpr, EnumConstantDecl (_, _, _, ecdi) -> ecdi.ecdi_init_expr | _, _ diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 0987353eb..07fbed450 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -454,7 +454,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let exps = [(exp, typ)] in {empty_res_trans with exps; instrs} | Tfun _ | Tvoid | Tarray _ | TVar _ - -> assert false + -> CFrontend_config.unimplemented "fill_typ_with_zero on type %a" (Typ.pp Pp.text) typ in let res_trans = fill_typ_with_zero var_exp_typ in {res_trans with initd_exps= [fst var_exp_typ]} @@ -572,9 +572,12 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s -> CType_decl.get_record_typename ~tenv:context.tenv decl | _ -> assert false ) - | _ - -> assert false - (* di_parent_pointer should be always set for fields/ivars *) + | _ as decl + -> (* FIXME(t21762295): we do not expect this to happen but it does *) + CFrontend_config.incorrect_assumption + "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 in let field_name = CGeneral_utils.mk_class_field_name class_tname field_string in let field_exp = Exp.Lfield (obj_sil, field_name, class_typ) in @@ -844,8 +847,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s match stmt_list with | [a; i] -> (a, i) - (* Assumption: the statement list contains 2 elements, - the first is the array expr and the second the index *) + (* Assumption: the statement list contains 2 elements, the first is the array expr and the + second the index *) | _ -> assert false (* Let's get notified if the assumption is wrong...*) @@ -1013,9 +1016,14 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let act_params = let params = List.tl_exn (collect_exprs result_trans_subexprs) in if Int.equal (List.length params) (List.length params_stmt) then params - else ( - L.internal_error "ERROR: stmt_list and res_trans_par.exps must have same size@\n" ; - assert false ) + else + (* FIXME(t21762295) this is reachable *) + CFrontend_config.incorrect_assumption + "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) + (Pp.seq (Pp.to_string ~f:Clang_ast_j.string_of_stmt)) + params_stmt in let act_params = if is_cf_retain_release then (Exp.Const (Const.Cint IntLit.one), Typ.mk (Tint Typ.IBool)) @@ -1050,16 +1058,20 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let context = trans_state_pri.context in let procname = Procdesc.get_proc_name context.procdesc in let sil_loc = CLocation.get_sil_location si context in - (* first for method address, second for 'this' expression *) - assert (Int.equal (List.length result_trans_callee.exps) 2) ; + (* first for method address, second for 'this' expression and other parameters *) + assert (List.length result_trans_callee.exps >= 1) ; let sil_method, _ = List.hd_exn result_trans_callee.exps in let callee_pname = - match sil_method with Exp.Const Const.Cfun pn -> pn | _ -> assert false - (* method pointer not implemented, this shouldn't happen *) + match sil_method with + | Exp.Const Const.Cfun pn + -> 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 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 *) + (* 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 *) let result_trans_subexprs = let trans_state_param = {trans_state_pri with succ_nodes= []; var_exp_typ= None} in let instruction' = exec_with_self_exception (exec_with_glvalue_as_reference instruction) in @@ -1175,7 +1187,9 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s CMethod_trans.get_class_name_method_call_from_receiver_kind context obj_c_message_expr_info act_params in - raise (Self.SelfClassException class_name) (* alloc or new *) + (* alloc or new *) + (* FIXME(t21762295): we do not expect this to propagate to the top but it does *) + raise (Self.SelfClassException class_name) else if String.equal selector CFrontend_config.alloc || String.equal selector CFrontend_config.new_str then @@ -1489,8 +1503,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let root_nodes' = if root_nodes <> [] then root_nodes else op_res_trans.root_nodes in {op_res_trans with root_nodes= root_nodes'} | _ - -> L.(debug Capture Medium) "BinaryConditionalOperator not translated@." ; - assert false + -> CFrontend_config.unimplemented "BinaryConditionalOperator not translated" (* Translate a condition for if/loops statement. It shorts-circuit and/or. *) (* The invariant is that the translation of a condition always contains (at least) *) @@ -1810,7 +1823,11 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s (* succ_nodes will remove the temps *) {empty_res_trans with root_nodes= top_nodes; leaf_nodes= succ_nodes} | _ - -> assert false + -> (* TODO(t21762295) this raises sometimes *) + CFrontend_config.incorrect_assumption + "Unexpected Switch Statement sub-expression list: [%a]" + (Pp.semicolon_seq (Pp.to_string ~f:Clang_ast_j.string_of_stmt)) + switch_stmt_list and stmtExpr_trans trans_state stmt_list = let stmt = @@ -2058,7 +2075,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s | Tint _ | Tfloat _ | Tptr _ -> initListExpr_builtin_trans trans_state_pri init_stmt_info stmts var_exp var_typ | _ - -> assert false + -> CFrontend_config.unimplemented "InitListExp for var %a of type %a" Exp.pp var_exp + (Typ.pp Pp.text) var_typ in let nname = "InitListExp" in let res_trans = @@ -2185,8 +2203,10 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s | (RecordDecl _) :: var_decls' -> (* Record declaration is done in the beginning when procdesc is defined.*) collect_all_decl trans_state var_decls' next_nodes stmt_info - | _ - -> assert false + | decl :: _ + -> CFrontend_config.incorrect_assumption "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 (* stmt_list is ignored because it contains the same instructions as *) (* the init expression. We use the latter info. *) @@ -2196,15 +2216,19 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let open Clang_ast_t in match decl_list with | (VarDecl _) :: _ - -> (* Case for simple variable declarations*) - collect_all_decl trans_state decl_list succ_nodes stmt_info - | (CXXRecordDecl _) :: _ (*C++/C record decl treated in the same way *) | (RecordDecl _) :: _ + (* Case for simple variable declarations*) + | (CXXRecordDecl _) :: _ + (*C++/C record decl treated in the same way *) + | (RecordDecl _) :: _ -> (* Case for struct *) collect_all_decl trans_state decl_list succ_nodes stmt_info - | _ - -> L.(debug Capture Medium) - "WARNING: In DeclStmt found an unknown declaration type. RETURNING empty list of declaration. NEED TO BE FIXED" ; - empty_res_trans + | (TypedefDecl _) :: _ | (UsingDirectiveDecl _) :: _ + -> empty_res_trans + | decl :: _ + -> CFrontend_config.unimplemented "In DeclStmt found an unknown declaration type %s" + (Clang_ast_j.string_of_decl decl) + | [] + -> assert false in {res_trans with leaf_nodes= []} @@ -2246,7 +2270,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s how x.f = a is actually implemented by the runtime.*) and pseudoObjectExpr_trans trans_state stmt_list = L.(debug Capture Verbose) - " priority node free = '%s'@\n@." + " priority node free = '%s'@\n@\n" (string_of_bool (PriorityNode.is_priority_free trans_state)) ; let rec do_semantic_elements el = let open Clang_ast_t in @@ -2906,9 +2930,15 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s | NullStmt _, FallThroughAttr _ -> no_op_trans trans_state.succ_nodes | _ - -> assert false (* More cases to come. With the assert false we can find them *) ) + -> CFrontend_config.unimplemented + "attributedStmt [stmt] [attr] with:@\nstmt=%s@\nattr=%s@\n" + (Clang_ast_j.string_of_stmt stmt) (Clang_ast_j.string_of_attribute attr) ) | _ - -> assert false + -> CFrontend_config.unimplemented "attributedStmt with:@\nstmts=[%a]@\nattrs=[%a]@\n" + (Pp.semicolon_seq (Pp.to_string ~f:Clang_ast_j.string_of_stmt)) + stmts + (Pp.semicolon_seq (Pp.to_string ~f:Clang_ast_j.string_of_attribute)) + attrs and breakStmt_trans trans_state stmt_info = match trans_state.continuation with @@ -2986,9 +3016,9 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s | SwitchStmt (stmt_info, switch_stmt_list) -> switchStmt_trans trans_state stmt_info switch_stmt_list | CaseStmt _ - -> L.(debug Capture Verbose) - "FATAL: Passing from CaseStmt outside of SwitchStmt, terminating.@\n" ; - assert false + -> (* where do we even get case stmts outside of the switch stmt? (t21762295) *) + CFrontend_config.incorrect_assumption "Case statement outside of switch statement: %a" + (Pp.to_string ~f:Clang_ast_j.string_of_stmt) instr | StmtExpr (_, stmt_list, _) -> stmtExpr_trans trans_state stmt_list | ForStmt (stmt_info, [init; decl_stmt; cond; incr; body]) @@ -3167,9 +3197,105 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s | SubstNonTypeTemplateParmExpr _ | SubstNonTypeTemplateParmPackExpr _ | CXXDependentScopeMemberExpr _ - -> raise (CTrans_utils.TemplatedCodeException instr) - | s - -> raise (CTrans_utils.UnsupportedStatementException s) + -> raise + (CFrontend_config.unimplemented "Translation of templated code is unsupported: %a" + (Pp.to_string ~f:Clang_ast_j.string_of_stmt) instr) + | ForStmt (_, _) | WhileStmt (_, _) | DoStmt (_, _) | ObjCForCollectionStmt (_, _) + -> assert false + | MSAsmStmt _ + | CapturedStmt _ + | CoreturnStmt _ + | CoroutineBodyStmt _ + | AddrLabelExpr _ + | ArrayTypeTraitExpr _ + | AsTypeExpr _ + | AtomicExpr _ + | CXXFoldExpr _ + | CXXInheritedCtorInitExpr _ + | CXXUnresolvedConstructExpr _ + | CXXUuidofExpr _ + | CUDAKernelCallExpr _ + | ChooseExpr _ + | ConvertVectorExpr _ + | CoawaitExpr _ + | CoyieldExpr _ + | DependentCoawaitExpr _ + | DependentScopeDeclRefExpr _ + | DesignatedInitExpr _ + | DesignatedInitUpdateExpr _ + | ExpressionTraitExpr _ + | FunctionParmPackExpr _ + | ImaginaryLiteral _ + | MSPropertyRefExpr _ + | MSPropertySubscriptExpr _ + | NoInitExpr _ + | OMPArraySectionExpr _ + | ObjCAvailabilityCheckExpr _ + | ObjCIsaExpr _ + | ObjCSubscriptRefExpr _ + | UnresolvedLookupExpr _ + | UnresolvedMemberExpr _ + | PackExpansionExpr _ + | ParenListExpr _ + | TypoExpr _ + | IndirectGotoStmt _ + | MSDependentExistsStmt _ + | OMPAtomicDirective _ + | OMPBarrierDirective _ + | OMPCancelDirective _ + | OMPCancellationPointDirective _ + | OMPCriticalDirective _ + | OMPFlushDirective _ + | OMPDistributeDirective _ + | OMPDistributeParallelForDirective _ + | OMPDistributeParallelForSimdDirective _ + | OMPDistributeSimdDirective _ + | OMPForDirective _ + | OMPForSimdDirective _ + | OMPParallelForDirective _ + | OMPParallelForSimdDirective _ + | OMPSimdDirective _ + | OMPTargetParallelForSimdDirective _ + | OMPTargetSimdDirective _ + | OMPTargetTeamsDistributeDirective _ + | OMPTargetTeamsDistributeParallelForDirective _ + | OMPTargetTeamsDistributeParallelForSimdDirective _ + | OMPTargetTeamsDistributeSimdDirective _ + | OMPTaskLoopDirective _ + | OMPTaskLoopSimdDirective _ + | OMPTeamsDistributeDirective _ + | OMPTeamsDistributeParallelForDirective _ + | OMPTeamsDistributeParallelForSimdDirective _ + | OMPTeamsDistributeSimdDirective _ + | OMPMasterDirective _ + | OMPOrderedDirective _ + | OMPParallelDirective _ + | OMPParallelSectionsDirective _ + | OMPSectionDirective _ + | OMPSectionsDirective _ + | OMPSingleDirective _ + | OMPTargetDataDirective _ + | OMPTargetDirective _ + | OMPTargetEnterDataDirective _ + | OMPTargetExitDataDirective _ + | OMPTargetParallelDirective _ + | OMPTargetParallelForDirective _ + | OMPTargetTeamsDirective _ + | OMPTargetUpdateDirective _ + | OMPTaskDirective _ + | OMPTaskgroupDirective _ + | OMPTaskwaitDirective _ + | OMPTaskyieldDirective _ + | OMPTeamsDirective _ + | SEHExceptStmt _ + | SEHFinallyStmt _ + | SEHLeaveStmt _ + | SEHTryStmt _ + | DefaultStmt _ + -> raise + (CFrontend_config.unimplemented "Statement translation for kind %s: %a" + (Clang_ast_proj.get_stmt_kind_string instr) + (Pp.to_string ~f:Clang_ast_j.string_of_stmt) instr) (* Function similar to instruction function, but it takes C++ constructor initializer as an input parameter. *) diff --git a/infer/src/clang/cTrans_utils.ml b/infer/src/clang/cTrans_utils.ml index 78f8531da..64c9c1c00 100644 --- a/infer/src/clang/cTrans_utils.ml +++ b/infer/src/clang/cTrans_utils.ml @@ -14,10 +14,6 @@ module Hashtbl = Caml.Hashtbl module L = Logging -exception TemplatedCodeException of Clang_ast_t.stmt - -exception UnsupportedStatementException of Clang_ast_t.stmt - (* Extract the element of a singleton list. If the list is not a singleton *) (* It stops the computation giving a warning. We use this because we *) (* assume in many places that a list is just a singleton. We use the *) @@ -653,8 +649,7 @@ let rec get_type_from_exp_stmt stmt = | DeclRefExpr (_, _, _, info) -> do_decl_ref_exp info | _ - -> L.internal_error "Failing with: %s@\n%!" (Clang_ast_j.string_of_stmt stmt) ; - assert false + -> L.die InternalError "get_type_from_expr_stmt failure: %s" (Clang_ast_j.string_of_stmt stmt) module Self = struct exception SelfClassException of Typ.Name.t @@ -793,7 +788,7 @@ let is_dispatch_function stmt_list = try let arg_stmt = List.nth_exn arg_stmts block_arg_pos in if is_block_stmt arg_stmt then Some block_arg_pos else None - with Failure _ -> None ) + with Invalid_argument _ -> None ) | _ -> None ) | _ -> diff --git a/infer/src/clang/cTrans_utils.mli b/infer/src/clang/cTrans_utils.mli index 6edf6fdec..71fd1d296 100644 --- a/infer/src/clang/cTrans_utils.mli +++ b/infer/src/clang/cTrans_utils.mli @@ -36,10 +36,6 @@ type trans_result = ; initd_exps: Exp.t list ; is_cpp_call_virtual: bool } -exception TemplatedCodeException of Clang_ast_t.stmt - -exception UnsupportedStatementException of Clang_ast_t.stmt - val empty_res_trans : trans_result val undefined_expression : unit -> Exp.t diff --git a/infer/src/eradicate/AnnotatedSignature.ml b/infer/src/eradicate/AnnotatedSignature.ml index 18e7df1cd..e96a0d8b6 100644 --- a/infer/src/eradicate/AnnotatedSignature.ml +++ b/infer/src/eradicate/AnnotatedSignature.ml @@ -118,11 +118,9 @@ let mark proc_name ann asig (b, bs) = in let params' = let fail () = - L.internal_error - "INTERNAL ERROR: annotation for procedure %s has wrong number of arguments@." - (Typ.Procname.to_unique_id proc_name) ; - L.internal_error " ANNOTATED SIGNATURE: %a@." (pp proc_name) asig ; - assert false + L.die InternalError + "Annotation for procedure %s has wrong number of arguments.@\n Annotated signature: %a" + (Typ.Procname.to_unique_id proc_name) (pp proc_name) asig in let rec combine l1 l2 = match (l1, l2) with diff --git a/infer/src/eradicate/models.ml b/infer/src/eradicate/models.ml index 3946e6b32..ad4bd2056 100644 --- a/infer/src/eradicate/models.ml +++ b/infer/src/eradicate/models.ml @@ -44,9 +44,7 @@ module Inference = struct if String.is_empty s_old then 0 else try int_of_string s_old - with Failure _ -> - L.internal_error "int_of_string %s@." s_old ; - assert false + with Failure _ -> L.die InternalError "int_of_string %s" s_old in string_of_int (n + 1) diff --git a/infer/src/harness/inhabit.ml b/infer/src/harness/inhabit.ml index 10b7726f3..9e32de966 100644 --- a/infer/src/harness/inhabit.ml +++ b/infer/src/harness/inhabit.ml @@ -150,8 +150,7 @@ let rec inhabit_typ tenv typ cfg env = | Typ.Tfloat _ -> (Exp.Const (Const.Cfloat 0.0), env) | _ - -> L.internal_error "Couldn't inhabit typ: %a@." (Typ.pp Pp.text) typ ; - assert false + -> L.die InternalError "Couldn't inhabit typ: %a" (Typ.pp Pp.text) typ in let inhabited_exp, env' = inhabit_internal typ {env with cur_inhabiting= TypSet.add typ env.cur_inhabiting}