[log] die more appropriately

Summary:
- failwith police: no more `failwith`. Instead, use `Logging.die`.
- Introduce the `SimpleLogging` module for dying from modules where `Logging`
  cannot be used (usually because that would create a cyclic dependency).
- always log backtraces, and show backtraces on the console except for usage errors
- Also point out in the log file where the toplevel executions of infer happen

Reviewed By: jeremydubreil

Differential Revision: D5726362

fbshipit-source-id: d7a01fc
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent 3e660b05ee
commit 1c375a17ac

@ -84,7 +84,7 @@ let check_cfg_connectedness cfg =
let nodes = Procdesc.get_nodes pd in let nodes = Procdesc.get_nodes pd in
(* TODO (T20302015): also check the CFGs for the C-like procedures *) (* TODO (T20302015): also check the CFGs for the C-like procedures *)
if not Config.keep_going && Typ.Procname.is_java pname && List.exists ~f:broken_node nodes then if not Config.keep_going && Typ.Procname.is_java pname && List.exists ~f:broken_node nodes then
failwithf "Broken CFG on %a" Typ.Procname.pp pname L.(die InternalError) "Broken CFG on %a" Typ.Procname.pp pname
in in
let pdescs = get_all_procs cfg in let pdescs = get_all_procs cfg in
List.iter ~f:do_pdesc pdescs List.iter ~f:do_pdesc pdescs

@ -162,7 +162,7 @@ let of_sil ~include_array_indexes ~f_resolve_id exp typ =
| Some access_path | Some access_path
-> AccessPath access_path -> AccessPath access_path
| None | None
-> failwithf "Couldn't convert var expression %a to access path" Exp.pp exp -> L.(die InternalError) "Couldn't convert var expression %a to access path" Exp.pp exp
in in
of_sil_ exp typ of_sil_ exp typ

@ -84,10 +84,10 @@ let of_sil ~include_array_indexes ~f_resolve_id (instr: Sil.instr) =
| ap :: _ | ap :: _
-> ap -> ap
| [] | []
-> invalid_argf "Invalid pointer arithmetic expression %a used as LHS" Exp.pp lhs_exp -> L.(die InternalError)
) "Invalid pointer arithmetic expression %a used as LHS" Exp.pp lhs_exp )
| _ | _
-> invalid_argf "Non-assignable LHS expression %a" Exp.pp lhs_exp -> L.(die InternalError) "Non-assignable LHS expression %a" Exp.pp lhs_exp
in in
Instr (Assign (lhs_access_path, exp_of_sil rhs_exp typ, loc)) Instr (Assign (lhs_access_path, exp_of_sil rhs_exp typ, loc))
| Call (ret_opt, call_exp, formals, loc, call_flags) | Call (ret_opt, call_exp, formals, loc, call_flags)
@ -99,7 +99,7 @@ let of_sil ~include_array_indexes ~f_resolve_id (instr: Sil.instr) =
| AccessPath access_path | AccessPath access_path
-> Indirect access_path -> Indirect access_path
| call_exp | call_exp
-> invalid_argf "Unexpected call expression %a" HilExp.pp call_exp -> L.(die InternalError) "Unexpected call expression %a" HilExp.pp call_exp
in in
let formals = List.map ~f:(fun (exp, typ) -> exp_of_sil exp typ) formals in let formals = List.map ~f:(fun (exp, typ) -> exp_of_sil exp typ) formals in
Instr (Call (hil_ret, hil_call, formals, call_flags, loc)) Instr (Call (hil_ret, hil_call, formals, call_flags, loc))

@ -9,6 +9,7 @@
*) *)
open! IStd open! IStd
module F = Format module F = Format
module L = Logging
(** signed and unsigned integer literals *) (** signed and unsigned integer literals *)
type t = bool * Int64.t * bool type t = bool * Int64.t * bool
@ -108,7 +109,7 @@ let sub i1 i2 = add i1 (neg i2)
let shift_left (unsigned1, i1, ptr1) (_, i2, _) = let shift_left (unsigned1, i1, ptr1) (_, i2, _) =
match Int64.to_int i2 with match Int64.to_int i2 with
| None | None
-> failwithf "Shifting failed with operand %a" Int64.pp i2 -> L.(die InternalError) "Shifting failed with operand %a" Int64.pp i2
| Some i2 | Some i2
-> if i2 < 0 || i2 >= 64 then raise OversizedShift ; -> if i2 < 0 || i2 >= 64 then raise OversizedShift ;
let res = Int64.shift_left i1 i2 in let res = Int64.shift_left i1 i2 in
@ -117,7 +118,7 @@ let shift_left (unsigned1, i1, ptr1) (_, i2, _) =
let shift_right (unsigned1, i1, ptr1) (_, i2, _) = let shift_right (unsigned1, i1, ptr1) (_, i2, _) =
match Int64.to_int i2 with match Int64.to_int i2 with
| None | None
-> failwithf "Shifting failed with operand %a" Int64.pp i2 -> L.(die InternalError) "Shifting failed with operand %a" Int64.pp i2
| Some i2 | Some i2
-> if i2 < 0 || i2 >= 64 then raise OversizedShift ; -> if i2 < 0 || i2 >= 64 then raise OversizedShift ;
let res = Int64.shift_right i1 i2 in let res = Int64.shift_right i1 i2 in

@ -227,7 +227,7 @@ let get_translation_unit pvar =
| Global_var (tu, _, _, _) | Global_var (tu, _, _, _)
-> tu -> tu
| _ | _
-> invalid_argf "Expected a global variable" -> L.(die InternalError) "Expected a global variable"
let is_compile_constant pvar = match pvar.pv_kind with Global_var (_, b, _, _) -> b | _ -> false let is_compile_constant pvar = match pvar.pv_kind with Global_var (_, b, _, _) -> b | _ -> false

@ -8,6 +8,7 @@
*) *)
open! IStd open! IStd
module L = Logging
(* internally it uses reversed list to store qualified name, for example: ["get", "shared_ptr<int>", "std"]*) (* internally it uses reversed list to store qualified name, for example: ["get", "shared_ptr<int>", "std"]*)
type t = string list [@@deriving compare] type t = string list [@@deriving compare]
@ -27,13 +28,13 @@ let strip_template_args quals =
let append_template_args_to_last quals ~args = let append_template_args_to_last quals ~args =
match quals with match quals with
| [last; _] when String.contains last '<' | [last; _] when String.contains last '<'
-> failwithf -> L.(die InternalError)
"expected qualified name without template args, but got %s, the last qualifier of %s" last "expected qualified name without template args, but got %s, the last qualifier of %s" last
(String.concat ~sep:", " quals) (String.concat ~sep:", " quals)
| last :: rest | last :: rest
-> (last ^ args) :: rest -> (last ^ args) :: rest
| [] | []
-> failwith "expected non-empty qualified name" -> L.(die InternalError) "expected non-empty qualified name"
let to_list = List.rev let to_list = List.rev
@ -82,7 +83,7 @@ module Match = struct
List.iter colon_splits ~f:(fun s -> List.iter colon_splits ~f:(fun s ->
(* Filter out the '<' in operator< and operator<= *) (* Filter out the '<' in operator< and operator<= *)
if not (String.is_prefix s ~prefix:"operator<") && String.contains s '<' then if not (String.is_prefix s ~prefix:"operator<") && String.contains s '<' then
failwithf "Unexpected template in fuzzy qualified name %s." qual_name ) ; L.(die InternalError) "Unexpected template in fuzzy qualified name %s." qual_name ) ;
of_qual_string qual_name of_qual_string qual_name
let of_fuzzy_qual_names fuzzy_qual_names = let of_fuzzy_qual_names fuzzy_qual_names =

@ -99,7 +99,7 @@ struct
else else
let visit_count' = old_state.visit_count + 1 in let visit_count' = old_state.visit_count + 1 in
if visit_count' > Config.max_widens then if visit_count' > Config.max_widens then
failwithf L.(die InternalError)
"Exceeded max widening threshold %d while analyzing %a. Please check your widening operator or increase the threshold" "Exceeded max widening threshold %d while analyzing %a. Please check your widening operator or increase the threshold"
Config.max_widens Typ.Procname.pp (Procdesc.get_proc_name pdesc) ; Config.max_widens Typ.Procname.pp (Procdesc.get_proc_name pdesc) ;
update_inv_map widened_pre visit_count' update_inv_map widened_pre visit_count'

@ -8,6 +8,7 @@
*) *)
open! IStd open! IStd
module L = Logging
module FileRenamings = struct module FileRenamings = struct
type renaming = {current: string; previous: string} [@@deriving compare] type renaming = {current: string; previous: string} [@@deriving compare]
@ -45,7 +46,7 @@ module FileRenamings = struct
| _ | _
-> raise (Yojson.Json_error "not a record") -> raise (Yojson.Json_error "not a record")
with Yojson.Json_error err -> with Yojson.Json_error err ->
failwithf L.(die UserError)
"Error parsing file renamings: %s@\nExpected JSON object of the following form: '%s', but instead got: '%s'" "Error parsing file renamings: %s@\nExpected JSON object of the following form: '%s', but instead got: '%s'"
err "{\"current\": \"aaa.java\", \"previous\": \"BBB.java\"}" err "{\"current\": \"aaa.java\", \"previous\": \"BBB.java\"}"
(Yojson.Basic.to_string assoc) (Yojson.Basic.to_string assoc)
@ -54,7 +55,7 @@ module FileRenamings = struct
| `List json_renamings | `List json_renamings
-> List.map ~f:renaming_of_assoc json_renamings -> List.map ~f:renaming_of_assoc json_renamings
| _ | _
-> failwithf "Expected JSON list but got '%s'" input -> L.(die UserError) "Expected JSON list but got '%s'" input
let from_json_file file : t = from_json (In_channel.read_all file) let from_json_file file : t = from_json (In_channel.read_all file)

@ -331,7 +331,8 @@ module IssuesJson = struct
-> (err_data.loc.Location.file, 0) -> (err_data.loc.Location.file, 0)
in in
if SourceFile.is_invalid source_file then if SourceFile.is_invalid source_file then
failwithf "Invalid source file for %a %a@.Trace: %a@." IssueType.pp key.err_name L.(die InternalError)
"Invalid source file for %a %a@.Trace: %a@." IssueType.pp key.err_name
Localise.pp_error_desc key.err_desc Errlog.pp_loc_trace err_data.loc_trace ; Localise.pp_error_desc key.err_desc Errlog.pp_loc_trace err_data.loc_trace ;
let should_report_source_file = let should_report_source_file =
not (SourceFile.is_infer_model source_file) || Config.debug_mode || Config.debug_exceptions not (SourceFile.is_infer_model source_file) || Config.debug_mode || Config.debug_exceptions
@ -741,39 +742,39 @@ let pp_issues_in_format (format_kind, (outf: Utils.outfile)) =
| Csv | Csv
-> IssuesCsv.pp_issues_of_error_log outf.fmt -> IssuesCsv.pp_issues_of_error_log outf.fmt
| Tests | Tests
-> failwith "Print issues as tests is not implemented" -> L.(die InternalError) "Print issues as tests is not implemented"
| Text | Text
-> IssuesTxt.pp_issues_of_error_log outf.fmt -> IssuesTxt.pp_issues_of_error_log outf.fmt
| Latex | Latex
-> failwith "Printing issues in latex is not implemented" -> L.(die InternalError) "Printing issues in latex is not implemented"
let pp_procs_in_format (format_kind, (outf: Utils.outfile)) = let pp_procs_in_format (format_kind, (outf: Utils.outfile)) =
match format_kind with match format_kind with
| Csv | Csv
-> ProcsCsv.pp_summary outf.fmt -> ProcsCsv.pp_summary outf.fmt
| Json | Latex | Tests | Text | Json | Latex | Tests | Text
-> failwith "Printing procs in json/latex/tests/text is not implemented" -> L.(die InternalError) "Printing procs in json/latex/tests/text is not implemented"
let pp_calls_in_format (format_kind, (outf: Utils.outfile)) = let pp_calls_in_format (format_kind, (outf: Utils.outfile)) =
match format_kind with match format_kind with
| Csv | Csv
-> CallsCsv.pp_calls outf.fmt -> CallsCsv.pp_calls outf.fmt
| Json | Tests | Text | Latex | Json | Tests | Text | Latex
-> failwith "Printing calls in json/tests/text/latex is not implemented" -> L.(die InternalError) "Printing calls in json/tests/text/latex is not implemented"
let pp_stats_in_format (format_kind, _) = let pp_stats_in_format (format_kind, _) =
match format_kind with match format_kind with
| Csv | Csv
-> Stats.process_summary -> Stats.process_summary
| Json | Tests | Text | Latex | Json | Tests | Text | Latex
-> failwith "Printing stats in json/tests/text/latex is not implemented" -> L.(die InternalError) "Printing stats in json/tests/text/latex is not implemented"
let pp_summary_in_format (format_kind, (outf: Utils.outfile)) = let pp_summary_in_format (format_kind, (outf: Utils.outfile)) =
match format_kind with match format_kind with
| Latex | Latex
-> Summary.write_summary_latex outf.fmt -> Summary.write_summary_latex outf.fmt
| Json | Csv | Tests | Text | Json | Csv | Tests | Text
-> failwith "Printing summary in json/csv/tests/text is not implemented" -> L.(die InternalError) "Printing summary in json/csv/tests/text is not implemented"
let pp_issues_of_error_log error_filter linereader proc_loc_opt procname err_log bug_format_list = let pp_issues_of_error_log error_filter linereader proc_loc_opt procname err_log bug_format_list =
let pp_issues_in_format format = let pp_issues_in_format format =
@ -848,11 +849,11 @@ let pp_json_report_by_report_kind formats_by_report_kind fname =
| Text | Text
-> pp_text_of_report outf.fmt report -> pp_text_of_report outf.fmt report
| Json | Json
-> failwith "Printing issues from json does not support json output" -> L.(die InternalError) "Printing issues from json does not support json output"
| Csv | Csv
-> failwith "Printing issues from json does not support csv output" -> L.(die InternalError) "Printing issues from json does not support csv output"
| Latex | Latex
-> failwith "Printing issues from json does not support latex output" -> L.(die InternalError) "Printing issues from json does not support latex output"
in in
List.iter ~f:pp_json_issue format_list List.iter ~f:pp_json_issue format_list
in in
@ -869,7 +870,7 @@ let pp_json_report_by_report_kind formats_by_report_kind fname =
in in
List.iter ~f:pp_report_by_report_kind formats_by_report_kind List.iter ~f:pp_report_by_report_kind formats_by_report_kind
| Error error | Error error
-> failwithf "Error reading '%s': %s" fname error -> L.(die UserError) "Error reading '%s': %s" fname error
let pp_lint_issues_by_report_kind formats_by_report_kind error_filter linereader procname error_log = let pp_lint_issues_by_report_kind formats_by_report_kind error_filter linereader procname error_log =
let pp_summary_by_report_kind (report_kind, format_list) = let pp_summary_by_report_kind (report_kind, format_list) =

@ -8,6 +8,7 @@
*) *)
open! IStd open! IStd
open! PVariant open! PVariant
module L = Logging
let aggregated_stats_filename = "aggregated_stats.json" let aggregated_stats_filename = "aggregated_stats.json"
@ -51,22 +52,18 @@ let find_stats_files_in_dir dir =
{frontend_paths; backend_paths; reporting_paths} {frontend_paths; backend_paths; reporting_paths}
let load_data_from_infer_deps file = let load_data_from_infer_deps file =
let error msg = Printf.sprintf ("Error reading '%s': " ^^ msg) file in
let extract_target_and_path line = let extract_target_and_path line =
match Str.split_delim (Str.regexp (Str.quote "\t")) line with match String.split ~on:'\t' line with
| target :: _ :: path :: _ | target :: _ :: path :: _
-> if dir_exists path then (target, path) -> if dir_exists path then Ok (target, path)
else raise (Failure ("path '" ^ path ^ "' is not a valid directory")) else Error (error "path '%s' is not a valid directory" path)
| _ | _
-> raise (Failure "malformed input") -> Error (error "malformed input")
in in
let lines = Utils.read_file file in let parse_lines lines = List.map lines ~f:extract_target_and_path |> Result.all in
try Utils.read_file file |> Result.map_error ~f:(fun msg -> error "%s" msg)
match lines with |> Result.bind ~f:parse_lines
| Ok l
-> Ok (List.map ~f:extract_target_and_path l)
| Error error
-> raise (Failure (Printf.sprintf "Error reading '%s': %s" file error))
with Failure msg -> Error msg
let collect_all_stats_files () = let collect_all_stats_files () =
let infer_out = Config.results_dir in let infer_out = Config.results_dir in
@ -138,7 +135,9 @@ let aggregate_stats_by_target tp =
let generate_files () = let generate_files () =
let infer_out = Config.results_dir in let infer_out = Config.results_dir in
let stats_files = collect_all_stats_files () in let stats_files = collect_all_stats_files () in
let origin = match stats_files with Ok origin -> origin | Error e -> failwith e in let origin =
match stats_files with Ok origin -> origin | Error e -> L.(die InternalError) "%s" e
in
let aggregated_frontend_stats_dir = Filename.concat infer_out Config.frontend_stats_dir_name in let aggregated_frontend_stats_dir = Filename.concat infer_out Config.frontend_stats_dir_name in
let aggregated_backend_stats_dir = Filename.concat infer_out Config.backend_stats_dir_name in let aggregated_backend_stats_dir = Filename.concat infer_out Config.backend_stats_dir_name in
let aggregated_reporting_stats_dir = Filename.concat infer_out Config.reporting_stats_dir_name in let aggregated_reporting_stats_dir = Filename.concat infer_out Config.reporting_stats_dir_name in

@ -8,6 +8,7 @@
*) *)
open! IStd open! IStd
module L = Logging
(** Module for builtin functions with their symbolic execution handler *) (** Module for builtin functions with their symbolic execution handler *)
@ -34,7 +35,7 @@ let builtin_functions = Typ.Procname.Hash.create 4
let check_register_populated () = let check_register_populated () =
(* check if BuiltinDefn were loaded before accessing register *) (* check if BuiltinDefn were loaded before accessing register *)
if Int.equal (Typ.Procname.Hash.length builtin_functions) 0 then if Int.equal (Typ.Procname.Hash.length builtin_functions) 0 then
failwith "Builtins were not initialized" L.(die InternalError) "Builtins were not initialized"
(** check if the function is a builtin *) (** check if the function is a builtin *)
let is_registered name = let is_registered name =

@ -126,7 +126,7 @@ let iterate_callbacks call_graph exe_env =
let analyze_proc_name pname = let analyze_proc_name pname =
match Ondemand.get_proc_desc pname with match Ondemand.get_proc_desc pname with
| None | None
-> failwithf "Could not find proc desc for %a" Typ.Procname.pp pname -> L.(die InternalError) "Could not find proc desc for %a" Typ.Procname.pp pname
| Some pdesc | Some pdesc
-> ignore (Ondemand.analyze_proc_desc pdesc pdesc) -> ignore (Ondemand.analyze_proc_desc pdesc pdesc)
in in

@ -25,7 +25,7 @@ let frame_id_of_summary stacktree =
let short_name = List.hd_exn (Str.split (Str.regexp "(") stacktree.Stacktree_j.method_name) in let short_name = List.hd_exn (Str.split (Str.regexp "(") stacktree.Stacktree_j.method_name) in
match stacktree.Stacktree_j.location with match stacktree.Stacktree_j.location with
| None | None
-> failwith -> L.(die InternalError)
"Attempted to take signature of a frame without location information. This is undefined." "Attempted to take signature of a frame without location information. This is undefined."
| Some {line= Some line_num; file} | Some {line= Some line_num; file}
-> F.sprintf "%s(%s:%d)" short_name (Filename.basename file) line_num -> F.sprintf "%s(%s:%d)" short_name (Filename.basename file) line_num

@ -149,8 +149,8 @@ let java_global_tenv =
( lazy ( lazy
( match Tenv.load_from_file DB.global_tenv_fname with ( match Tenv.load_from_file DB.global_tenv_fname with
| None | None
-> failwithf "Could not load the global tenv at path %s@." -> L.(die InternalError)
(DB.filename_to_string DB.global_tenv_fname) "Could not load the global tenv at path '%s'" (DB.filename_to_string DB.global_tenv_fname)
| Some tenv | Some tenv
-> tenv ) ) -> tenv ) )
@ -166,10 +166,11 @@ let get_tenv exe_env proc_name =
| Some tenv | Some tenv
-> tenv -> tenv
| None | None
-> failwithf "get_tenv: tenv not found for %a in file %s" Typ.Procname.pp proc_name -> L.(die InternalError)
"get_tenv: tenv not found for %a in file '%s'" Typ.Procname.pp proc_name
(DB.filename_to_string file_data.tenv_file) ) (DB.filename_to_string file_data.tenv_file) )
| None | None
-> failwithf "get_tenv: file_data not found for %a" Typ.Procname.pp proc_name -> L.(die InternalError) "get_tenv: file_data not found for %a" Typ.Procname.pp proc_name
(** return the cfg associated to the procedure *) (** return the cfg associated to the procedure *)
let get_cfg exe_env pname = let get_cfg exe_env pname =

@ -118,7 +118,8 @@ let () =
-> (* at least one report must be passed in input to compute differential *) -> (* at least one report must be passed in input to compute differential *)
( match (Config.report_current, Config.report_previous) with ( match (Config.report_current, Config.report_previous) with
| None, None | None, None
-> failwith "Expected at least one argument among 'report-current' and 'report-previous'\n" -> L.(die UserError)
"Expected at least one argument among 'report-current' and 'report-previous'"
| _ | _
-> () ) ; -> () ) ;
ReportDiff.reportdiff ~current_report:Config.report_current ReportDiff.reportdiff ~current_report:Config.report_current

@ -178,7 +178,7 @@ module OverridesMatcher = struct
-> is_subtype mp.class_name -> is_subtype mp.class_name
&& Option.value_map ~f:(match_method language proc_name) ~default:false mp.method_name && Option.value_map ~f:(match_method language proc_name) ~default:false mp.method_name
| _ | _
-> failwith "Expecting method pattern" -> L.(die UserError) "Expecting method pattern"
in in
List.exists ~f:is_matching patterns List.exists ~f:is_matching patterns
end end
@ -229,7 +229,9 @@ let patterns_of_json_with_key (json_key, json) =
| `String s | `String s
-> s :: accu -> s :: accu
| _ | _
-> failwith ("Unrecognised parameters in " ^ Yojson.Basic.to_string (`Assoc assoc)) -> L.(die UserError)
"Unrecognised parameters in %s"
(Yojson.Basic.to_string (`Assoc assoc))
in in
List.rev (List.fold ~f:collect ~init:[] l) List.rev (List.fold ~f:collect ~init:[] l)
in in
@ -244,7 +246,7 @@ let patterns_of_json_with_key (json_key, json) =
| key, _ when String.equal key "language" | key, _ when String.equal key "language"
-> mp -> mp
| _ | _
-> failwith ("Fails to parse " ^ Yojson.Basic.to_string (`Assoc assoc)) -> L.(die UserError) "Failed to parse %s" (Yojson.Basic.to_string (`Assoc assoc))
in in
List.fold ~f:loop ~init:default_method_pattern assoc List.fold ~f:loop ~init:default_method_pattern assoc
and create_string_contains assoc = and create_string_contains assoc =
@ -254,7 +256,7 @@ let patterns_of_json_with_key (json_key, json) =
| key, _ when String.equal key "language" | key, _ when String.equal key "language"
-> sc -> sc
| _ | _
-> failwith ("Fails to parse " ^ Yojson.Basic.to_string (`Assoc assoc)) -> L.(die UserError) "Failed to parse %s" (Yojson.Basic.to_string (`Assoc assoc))
in in
List.fold ~f:loop ~init:default_source_contains assoc List.fold ~f:loop ~init:default_source_contains assoc
in in

@ -157,8 +157,9 @@ let analyze_proc_desc curr_pdesc callee_pdesc : Specs.summary option =
let proc_attributes = Procdesc.get_attributes callee_pdesc in let proc_attributes = Procdesc.get_attributes callee_pdesc in
match !callbacks_ref with match !callbacks_ref with
| None | None
-> failwithf "No callbacks registered to analyze proc desc %a when analyzing %a@." -> L.(die InternalError)
Typ.Procname.pp callee_pname Typ.Procname.pp (Procdesc.get_proc_name curr_pdesc) "No callbacks registered to analyze proc desc %a when analyzing %a@." Typ.Procname.pp
callee_pname Typ.Procname.pp (Procdesc.get_proc_name curr_pdesc)
| Some callbacks | Some callbacks
-> if should_be_analyzed callee_pname proc_attributes then -> if should_be_analyzed callee_pname proc_attributes then
Some (run_proc_analysis callbacks.analyze_ondemand curr_pdesc callee_pdesc) Some (run_proc_analysis callbacks.analyze_ondemand curr_pdesc callee_pdesc)
@ -170,8 +171,9 @@ let analyze_proc_desc curr_pdesc callee_pdesc : Specs.summary option =
let analyze_proc_name curr_pdesc callee_pname : Specs.summary option = let analyze_proc_name curr_pdesc callee_pname : Specs.summary option =
match !callbacks_ref with match !callbacks_ref with
| None | None
-> failwithf "No callbacks registered to analyze proc name %a when analyzing %a@." -> L.(die InternalError)
Typ.Procname.pp callee_pname Typ.Procname.pp (Procdesc.get_proc_name curr_pdesc) "No callbacks registered to analyze proc name %a when analyzing %a@." Typ.Procname.pp
callee_pname Typ.Procname.pp (Procdesc.get_proc_name curr_pdesc)
| Some callbacks | Some callbacks
-> if procedure_should_be_analyzed callee_pname then -> if procedure_should_be_analyzed callee_pname then
match callbacks.get_proc_desc callee_pname with match callbacks.get_proc_desc callee_pname with

@ -10,6 +10,7 @@
open! IStd open! IStd
open! PVariant open! PVariant
module L = Logging
(** mutate the cfg/cg to add dynamic dispatch handling *) (** mutate the cfg/cg to add dynamic dispatch handling *)
let add_dispatch_calls pdesc cg tenv = let add_dispatch_calls pdesc cg tenv =
@ -160,7 +161,8 @@ module NullifyTransferFunctions = struct
| Sil.Store _ | Prune _ | Declare_locals _ | Remove_temps _ | Abstract _ | Sil.Store _ | Prune _ | Declare_locals _ | Remove_temps _ | Abstract _
-> astate -> astate
| Sil.Nullify _ | Sil.Nullify _
-> failwith "Should not add nullify instructions before running nullify analysis!" -> L.(die InternalError)
"Should not add nullify instructions before running nullify analysis!"
in in
if is_last_instr_in_node instr node then postprocess astate' node extras else astate' if is_last_instr_in_node instr node then postprocess astate' node extras else astate'
end end
@ -236,8 +238,7 @@ let do_liveness pdesc tenv =
LivenessAnalysis.exec_cfg liveness_proc_cfg (ProcData.make_default pdesc tenv) ~initial LivenessAnalysis.exec_cfg liveness_proc_cfg (ProcData.make_default pdesc tenv) ~initial
~debug:false ~debug:false
in in
add_nullify_instrs pdesc tenv liveness_inv_map ; add_nullify_instrs pdesc tenv liveness_inv_map ; Procdesc.signal_did_preanalysis pdesc
Procdesc.signal_did_preanalysis pdesc
let do_abstraction pdesc = let do_abstraction pdesc =
add_abstraction_instructions pdesc ; Procdesc.signal_did_preanalysis pdesc add_abstraction_instructions pdesc ; Procdesc.signal_did_preanalysis pdesc

@ -1734,7 +1734,8 @@ let expand_hpred_pointer =
Exp.Sizeof {sizeof_data with typ= Typ.mk (Tstruct name)} Exp.Sizeof {sizeof_data with typ= Typ.mk (Tstruct name)}
| _ | _
-> (* type of struct at adr_base and of contents are both unknown: give up *) -> (* type of struct at adr_base and of contents are both unknown: give up *)
raise (Failure "expand_hpred_pointer: Unexpected non-sizeof type in Lfield") L.(die InternalError)
"expand_hpred_pointer: Unexpected non-sizeof type in Lfield"
in in
let hpred' = let hpred' =
Sil.Hpointsto (adr_base, Estruct ([(fld, cnt)], Sil.inst_none), cnt_texp') Sil.Hpointsto (adr_base, Estruct ([(fld, cnt)], Sil.inst_none), cnt_texp')
@ -1746,7 +1747,7 @@ let expand_hpred_pointer =
| Exp.Sizeof ({typ= t_} as sizeof_data) | Exp.Sizeof ({typ= t_} as sizeof_data)
-> Exp.Sizeof {sizeof_data with typ= Typ.mk (Tarray (t_, None, None))} -> Exp.Sizeof {sizeof_data with typ= Typ.mk (Tarray (t_, None, None))}
| _ | _
-> raise (Failure "expand_hpred_pointer: Unexpected non-sizeof type in Lindex") -> L.(die InternalError) "expand_hpred_pointer: Unexpected non-sizeof type in Lindex"
in in
let len = let len =
match t' with match t' with

@ -8,6 +8,7 @@
*) *)
open! IStd open! IStd
module L = Logging
type log_t = type log_t =
?loc:Location.t -> ?node_id:int * int -> ?session:int -> ?ltr:Errlog.loc_trace ?loc:Location.t -> ?node_id:int * int -> ?session:int -> ?ltr:Errlog.loc_trace
@ -56,7 +57,7 @@ let log_issue_deprecated ?(store_summary= false) err_kind proc_name ?loc ?node_i
(* TODO (#16348004): This is currently needed as ThreadSafety works as a cluster checker *) (* TODO (#16348004): This is currently needed as ThreadSafety works as a cluster checker *)
Specs.store_summary summary Specs.store_summary summary
| None | None
-> failwithf -> L.(die InternalError)
"Trying to report error on procedure %a, but cannot because no summary exists for this procedure. Did you mean to log the error on the caller of %a instead?" "Trying to report error on procedure %a, but cannot because no summary exists for this procedure. Did you mean to log the error on the caller of %a instead?"
Typ.Procname.pp proc_name Typ.Procname.pp proc_name Typ.Procname.pp proc_name Typ.Procname.pp proc_name

@ -607,7 +607,8 @@ let rec get_summary proc_name =
let get_summary_unsafe s proc_name = let get_summary_unsafe s proc_name =
match get_summary proc_name with match get_summary proc_name with
| None | None
-> failwithf "[%s] Specs.get_summary_unsafe: %a Not found" s Typ.Procname.pp proc_name -> L.(die InternalError)
"[%s] Specs.get_summary_unsafe: %a Not found" s Typ.Procname.pp proc_name
| Some summary | Some summary
-> summary -> summary

@ -654,7 +654,7 @@ let resolve_virtual_pname tenv prop actuals callee_pname call_flags : Typ.Procna
-> (* default mode for Java virtual calls: resolution only *) -> (* default mode for Java virtual calls: resolution only *)
[resolved_target] ) [resolved_target] )
| _ | _
-> failwith "A virtual call must have a receiver" -> L.(die InternalError) "A virtual call must have a receiver"
(** Resolve the name of the procedure to call based on the type of the arguments *) (** Resolve the name of the procedure to call based on the type of the arguments *)
let resolve_java_pname tenv prop args pname_java call_flags : Typ.Procname.java = let resolve_java_pname tenv prop args pname_java call_flags : Typ.Procname.java =
@ -1413,7 +1413,7 @@ and add_constraints_on_actuals_by_ref tenv prop actuals_by_ref callee_pname call
| Exp.Lvar _ | Exp.Var _ | Exp.Lvar _ | Exp.Var _
-> Pvar.mk_abduced_ref_param callee_pname actual_index callee_loc -> Pvar.mk_abduced_ref_param callee_pname actual_index callee_loc
| _ | _
-> failwithf "Unexpected variable expression %a" Exp.pp actual -> L.(die InternalError) "Unexpected variable expression %a" Exp.pp actual
in in
let already_has_abduced_retval p = let already_has_abduced_retval p =
List.exists List.exists
@ -1439,7 +1439,8 @@ and add_constraints_on_actuals_by_ref tenv prop actuals_by_ref callee_pname call
let prop', fresh_fp_var = add_to_footprint tenv abduced typ prop in let prop', fresh_fp_var = add_to_footprint tenv abduced typ prop in
(prop', Sil.Eexp (fresh_fp_var, Sil.Inone)) (prop', Sil.Eexp (fresh_fp_var, Sil.Inone))
| _ | _
-> failwith ("No need for abduction on non-pointer type " ^ Typ.to_string actual_typ) -> L.(die InternalError)
"No need for abduction on non-pointer type %s" (Typ.to_string actual_typ)
in in
let filtered_sigma = let filtered_sigma =
List.map List.map

@ -12,6 +12,7 @@
open! IStd open! IStd
module F = Format module F = Format
module YBU = Yojson.Basic.Util module YBU = Yojson.Basic.Util
module L = SimpleLogging
let ( = ) = String.equal let ( = ) = String.equal
@ -34,7 +35,7 @@ let strict_mode_env_var = "INFER_STRICT_MODE"
let strict_mode = is_env_var_set strict_mode_env_var let strict_mode = is_env_var_set strict_mode_env_var
let warnf = let warnf =
if strict_mode then failwithf if strict_mode then fun fmt -> L.(die UserError) fmt
else if not is_originator then fun fmt -> F.ifprintf F.err_formatter fmt else if not is_originator then fun fmt -> F.ifprintf F.err_formatter fmt
else F.eprintf else F.eprintf
@ -183,7 +184,7 @@ let check_no_duplicates desc_list =
| [] | [_] | [] | [_]
-> true -> true
| (x, _, _) :: (y, _, _) :: _ when x <> "" && x = y | (x, _, _) :: (y, _, _) :: _ when x <> "" && x = y
-> failwith ("Multiple definitions of command line option: " ^ x) -> L.(die InternalError) "Multiple definitions of command line option: %s" x
| _ :: tl | _ :: tl
-> check_for_duplicates_ tl -> check_for_duplicates_ tl
in in
@ -286,7 +287,7 @@ let deprecate_desc parse_mode ~long ~short ~deprecated desc =
-> spec -> spec
in in
let deprecated_decode_json ~inferconfig_dir j = let deprecated_decode_json ~inferconfig_dir j =
warnf "WARNING: in .inferconfig: '%s' is deprecated. Use '%s' instead.@." deprecated long ; warnf "WARNING: in .inferconfig: '%s' is deprecated. Use '%s' instead." deprecated long ;
desc.decode_json ~inferconfig_dir j desc.decode_json ~inferconfig_dir j
in in
{ long= "" { long= ""
@ -510,9 +511,10 @@ let mk_path_helper ~setter ~default_to_string ~default ~deprecated ~long ~short
let abs_path = normalize_path_in_args_being_parsed ~is_anon_arg:false str in let abs_path = normalize_path_in_args_being_parsed ~is_anon_arg:false str in
setter var abs_path) ~mk_spec:(fun set -> String set ) setter var abs_path) ~mk_spec:(fun set -> String set )
let mk_path ~default ?(deprecated= []) ~long ?short ?parse_mode ?in_help ?(meta= "path") = let mk_path ~default ?(f= Fn.id) ?(deprecated= []) ~long ?short ?parse_mode ?in_help
?(meta= "path") =
mk_path_helper mk_path_helper
~setter:(fun var x -> var := x) ~setter:(fun var x -> var := f x)
~decode_json:(path_json_decoder ~long) ~decode_json:(path_json_decoder ~long)
~default_to_string:(fun s -> s) ~default_to_string:(fun s -> s)
~default ~deprecated ~long ~short ~parse_mode ~in_help ~meta ~default ~deprecated ~long ~short ~parse_mode ~in_help ~meta
@ -975,7 +977,7 @@ let show_manual ?internal_section format default_doc command_opt =
| Some command_doc, _, _ | Some command_doc, _, _
-> command_doc -> command_doc
| None, _, _ | None, _, _
-> invalid_argf "No manual for internal command %s" (string_of_command command) -> L.(die InternalError) "No manual for internal command %s" (string_of_command command)
in in
let pp_meta f meta = let pp_meta f meta =
match meta with "" -> () | meta -> F.fprintf f " $(i,%s)" (Cmdliner.Manpage.escape meta) match meta with "" -> () | meta -> F.fprintf f " $(i,%s)" (Cmdliner.Manpage.escape meta)

@ -122,7 +122,7 @@ val mk_string_list : ?default:string list -> ?f:(string -> string) -> string lis
An option "--[long]-reset" is automatically created that resets the list to [] when found on the An option "--[long]-reset" is automatically created that resets the list to [] when found on the
command line. *) command line. *)
val mk_path : default:string -> string ref t val mk_path : default:string -> ?f:(string -> string) -> string ref t
(** like [mk_string] but will resolve the string into an absolute path so that children processes (** like [mk_string] but will resolve the string into an absolute path so that children processes
agree on the absolute path that the option represents *) agree on the absolute path that the option represents *)

@ -14,8 +14,9 @@ open! PVariant
(** Configuration values: either constant, determined at compile time, or set at startup (** Configuration values: either constant, determined at compile time, or set at startup
time by system calls, environment variables, or command line options *) time by system calls, environment variables, or command line options *)
module CLOpt = CommandLineOption
module F = Format module F = Format
module CLOpt = CommandLineOption
module L = SimpleLogging
type analyzer = type analyzer =
| BiAbduction | BiAbduction
@ -1555,19 +1556,15 @@ and specs_library =
(* Given a filename with a list of paths, convert it into a list of string iff they are (* Given a filename with a list of paths, convert it into a list of string iff they are
absolute *) absolute *)
let read_specs_dir_list_file fname = let read_specs_dir_list_file fname =
let validate_path path =
if Filename.is_relative path then
failwith ("Failing because path " ^ path ^ " is not absolute")
in
match Utils.read_file (resolve fname) with match Utils.read_file (resolve fname) with
| Ok pathlist | Ok pathlist
-> List.iter ~f:validate_path pathlist ; pathlist -> pathlist
| Error error | Error error
-> failwithf "cannot read file '%s' from cwd '%s': %s" fname (Sys.getcwd ()) error -> L.(die UserError) "cannot read file '%s' from cwd '%s': %s" fname (Sys.getcwd ()) error
in in
(* Add the newline-separated directories listed in <file> to the list of directories to be (* Add the newline-separated directories listed in <file> to the list of directories to be
searched for .spec files *) searched for .spec files *)
CLOpt.mk_string ~deprecated:["specs-dir-list-file"; "-specs-dir-list-file"] CLOpt.mk_path ~deprecated:["specs-dir-list-file"; "-specs-dir-list-file"]
~long:"specs-library-index" ~default:"" ~long:"specs-library-index" ~default:""
~f:(fun file -> ~f:(fun file ->
specs_library := read_specs_dir_list_file file @ !specs_library ; specs_library := read_specs_dir_list_file file @ !specs_library ;
@ -1787,12 +1784,34 @@ let post_parsing_initialization command_opt =
| `None | `None
-> () ) ; -> () ) ;
if !version <> `None || !help <> `None then exit 0 ; if !version <> `None || !help <> `None then exit 0 ;
(* Core sets a verbose exception handler by default, with backtrace. This is good for developers let uncaught_exception_handler exn raw_backtrace =
but in user-mode we want something lighter weight. *) let backtrace, should_print_backtrace_default =
if not !developer_mode then match exn with
Caml.Printexc.set_uncaught_exception_handler (fun exn _ -> | L.InferExternalError (_, bt) | L.InferInternalError (_, bt)
let exn_msg = match exn with Failure msg -> msg | _ -> Caml.Printexc.to_string exn in -> (bt, true)
Format.eprintf "ERROR: %s@." exn_msg ) ; | L.InferUserError (_, bt)
-> (bt, false)
| _
-> (Caml.Printexc.raw_backtrace_to_string raw_backtrace, true)
in
let print_exception () =
match exn with
| Failure msg
-> F.eprintf "ERROR: %s@\n" msg
| L.InferExternalError (msg, _)
-> F.eprintf "External Error: %s@\n" msg
| L.InferInternalError (msg, _)
-> F.eprintf "Internal Error: %s@\n" msg
| L.InferUserError (msg, _)
-> F.eprintf "Usage Error: %s@\n" msg
| _
-> F.eprintf "Uncaught error: %s@\n" (Exn.to_string exn)
in
if should_print_backtrace_default || !developer_mode then prerr_endline backtrace ;
print_exception () ;
exit (L.exit_code_of_exception exn)
in
Caml.Printexc.set_uncaught_exception_handler uncaught_exception_handler ;
F.set_margin !margin ; F.set_margin !margin ;
let set_minor_heap_size nMb = let set_minor_heap_size nMb =
(* increase the minor heap size to speed up gc *) (* increase the minor heap size to speed up gc *)
@ -1853,7 +1872,7 @@ let process_iphoneos_target_sdk_version_path_regex args =
| Some (path, version) | Some (path, version)
-> {path= Str.regexp path; version} -> {path= Str.regexp path; version}
| None | None
-> failwithf -> L.(die UserError)
"Incorrect format for the option iphoneos-target-sdk_version-path-regex. The correct format is path:version but got %s" "Incorrect format for the option iphoneos-target-sdk_version-path-regex. The correct format is path:version but got %s"
arg arg
in in

@ -130,7 +130,7 @@ let file_modified_time ?(symlink= false) fname =
try try
let stat = (if symlink then Unix.lstat else Unix.stat) fname in let stat = (if symlink then Unix.lstat else Unix.stat) fname in
stat.Unix.st_mtime stat.Unix.st_mtime
with Unix.Unix_error _ -> failwithf "File %s does not exist." fname with Unix.Unix_error _ -> L.(die InternalError) "File %s does not exist." fname
let filename_create_dir fname = let filename_create_dir fname =
let dirname = Filename.dirname fname in let dirname = Filename.dirname fname in
@ -172,7 +172,7 @@ let read_file_with_lock dir fname =
Unix.lockf fd ~mode:Unix.F_RLOCK ~len:0L ; Unix.lockf fd ~mode:Unix.F_RLOCK ~len:0L ;
let buf = read_whole_file fd in let buf = read_whole_file fd in
Unix.lockf fd ~mode:Unix.F_ULOCK ~len:0L ; Unix.close fd ; Some buf Unix.lockf fd ~mode:Unix.F_ULOCK ~len:0L ; Unix.close fd ; Some buf
with Unix.Unix_error _ -> failwith "read_file_with_lock: Unix error" with Unix.Unix_error _ -> L.(die ExternalError) "read_file_with_lock: Unix error"
with Unix.Unix_error _ -> None with Unix.Unix_error _ -> None
(** {2 Results Directory} *) (** {2 Results Directory} *)
@ -217,7 +217,7 @@ module Results_dir = struct
(** initialize the results directory *) (** initialize the results directory *)
let init source = let init source =
if SourceFile.is_invalid source then invalid_arg "Invalid source file passed" ; if SourceFile.is_invalid source then L.(die InternalError) "Invalid source file passed" ;
Utils.create_dir Config.results_dir ; Utils.create_dir Config.results_dir ;
Utils.create_dir specs_dir ; Utils.create_dir specs_dir ;
Utils.create_dir (path_to_filename Abs_root [Config.attributes_dir_name]) ; Utils.create_dir (path_to_filename Abs_root [Config.attributes_dir_name]) ;
@ -245,7 +245,7 @@ module Results_dir = struct
| filename :: dir_path | filename :: dir_path
-> (filename, dir_path) -> (filename, dir_path)
| [] | []
-> raise (Failure "create_path") -> L.(die InternalError) "create_path"
in in
let full_fname = Filename.concat (create dir_path) filename in let full_fname = Filename.concat (create dir_path) filename in
Unix.openfile full_fname ~mode:Unix.([O_WRONLY; O_CREAT; O_TRUNC]) ~perm:0o777 Unix.openfile full_fname ~mode:Unix.([O_WRONLY; O_CREAT; O_TRUNC]) ~perm:0o777

@ -14,6 +14,7 @@ open! IStd
module F = Format module F = Format
module CLOpt = CommandLineOption module CLOpt = CommandLineOption
include SimpleLogging
(* log files *) (* log files *)
(* make a copy of [f] *) (* make a copy of [f] *)
@ -35,15 +36,9 @@ let dup_formatter fmt1 fmt2 =
; out_spaces= (fun n -> out_funs1.out_spaces n ; out_funs2.out_spaces n) } ; ; out_spaces= (fun n -> out_funs1.out_spaces n ; out_funs2.out_spaces n) } ;
f f
(* should be set up to emit to a file later on; initially a string buffer so that logging is not (* can be set up to emit to a file later on, but can also be left as-is and logging will only happen
lost in the meantime *) on the console *)
let log_file = let log_file = ref (F.err_formatter, `Console)
let b = Buffer.create 256 in
let fmt =
let f = F.formatter_of_buffer b in
if Config.print_logs then dup_formatter f F.err_formatter else f
in
ref (fmt, `Buffer b)
type formatters = type formatters =
{ file: F.formatter (** send to log file *) { file: F.formatter (** send to log file *)
@ -134,26 +129,20 @@ let close_logs () =
List.iter ~f:close_fmt !logging_formatters ; List.iter ~f:close_fmt !logging_formatters ;
let fmt, chan = !log_file in let fmt, chan = !log_file in
F.pp_print_flush fmt () ; F.pp_print_flush fmt () ;
match chan with match chan with `Console -> () | `Channel c -> Out_channel.close c
| `Buffer b
-> prerr_endline (Buffer.contents b)
| `Channel c
-> Out_channel.close c
let () = Epilogues.register ~f:close_logs "flushing logs and closing log file" let () = Epilogues.register ~f:close_logs "flushing logs and closing log file"
let log_k ~to_console ?(to_file= true) ~k (lazy formatters) = let log ~to_console ?(to_file= true) (lazy formatters) =
match (to_console, to_file) with match (to_console, to_file) with
| false, false | false, false
-> F.ikfprintf k F.std_formatter -> F.ifprintf F.std_formatter
| true, _ when not Config.print_logs | true, _ when not Config.print_logs
-> F.kfprintf k !formatters.console_file -> F.fprintf !formatters.console_file
| _ | _
-> (* to_console might be true, but in that case so is Config.print_logs so do not print to -> (* to_console might be true, but in that case so is Config.print_logs so do not print to
stderr because it will get logs from the log file already *) stderr because it will get logs from the log file already *)
F.kfprintf k !formatters.file F.fprintf !formatters.file
let log = log_k ~k:ignore
let debug_file_fmts = register_formatter "debug" let debug_file_fmts = register_formatter "debug"
@ -165,6 +154,8 @@ let external_error_file_fmts = register_formatter "extern err"
let internal_error_file_fmts = register_formatter "intern err" let internal_error_file_fmts = register_formatter "intern err"
let phase_file_fmts = register_formatter "phase"
let progress_file_fmts = register_formatter "progress" let progress_file_fmts = register_formatter "progress"
let result_file_fmts = register_formatter ~use_stdout:true "result" let result_file_fmts = register_formatter ~use_stdout:true "result"
@ -173,6 +164,8 @@ let user_warning_file_fmts = register_formatter "user warn"
let user_error_file_fmts = register_formatter "user err" let user_error_file_fmts = register_formatter "user err"
let phase fmt = log ~to_console:false phase_file_fmts fmt
let progress fmt = log ~to_console:(not Config.quiet) progress_file_fmts fmt let progress fmt = log ~to_console:(not Config.quiet) progress_file_fmts fmt
let progress_bar text = let progress_bar text =
@ -198,9 +191,7 @@ let progressbar_timeout_event failure_kind =
let user_warning fmt = log ~to_console:(not Config.quiet) user_warning_file_fmts fmt let user_warning fmt = log ~to_console:(not Config.quiet) user_warning_file_fmts fmt
let user_error_k ~k fmt = log_k ~to_console:(not Config.quiet) ~k user_error_file_fmts fmt let user_error fmt = log ~to_console:true user_error_file_fmts fmt
let user_error fmt = user_error_k ~k:ignore fmt
type debug_level = Quiet | Medium | Verbose [@@deriving compare] type debug_level = Quiet | Medium | Verbose [@@deriving compare]
@ -242,14 +233,9 @@ let environment_info fmt = log ~to_console:false environment_info_file_fmts fmt
let external_warning fmt = log ~to_console:(not Config.quiet) external_warning_file_fmts fmt let external_warning fmt = log ~to_console:(not Config.quiet) external_warning_file_fmts fmt
let external_error_k ~k fmt = log_k ~to_console:(not Config.quiet) ~k external_error_file_fmts fmt let external_error fmt = log ~to_console:(not Config.quiet) external_error_file_fmts fmt
let external_error fmt = external_error_k ~k:ignore fmt let internal_error fmt = log ~to_console:Config.developer_mode internal_error_file_fmts fmt
let internal_error_k ~k fmt =
log_k ~to_console:Config.developer_mode ~k internal_error_file_fmts fmt
let internal_error fmt = internal_error_k ~k:ignore fmt
(** Type of location in ml source: __POS__ *) (** Type of location in ml source: __POS__ *)
type ml_loc = string * int * int * int type ml_loc = string * int * int * int
@ -264,20 +250,24 @@ let pp_ml_loc_opt fmt ml_loc_opt =
if Config.developer_mode then if Config.developer_mode then
match ml_loc_opt with None -> () | Some ml_loc -> F.fprintf fmt "(%a)" pp_ml_loc ml_loc match ml_loc_opt with None -> () | Some ml_loc -> F.fprintf fmt "(%a)" pp_ml_loc ml_loc
type error = UserError | ExternalError | InternalError let log_of_kind error fmt =
match error with
(* exit code 2 is used by the OCaml runtime in cases of uncaught exceptions, avoid it *)
let exit_code_of_kind = function UserError -> 1 | ExternalError -> 10 | InternalError -> 3
let log_of_kind = function
| UserError | UserError
-> user_error_k -> log ~to_console:false user_error_file_fmts fmt
| ExternalError | ExternalError
-> external_error_k -> log ~to_console:false external_error_file_fmts fmt
| InternalError | InternalError
-> internal_error_k -> log ~to_console:false internal_error_file_fmts fmt
let die error msg = log_of_kind error ~k:(fun _ -> exit (exit_code_of_kind error)) msg let die error msg =
F.kasprintf
(fun s ->
(* backtraces contain line breaks, which results in lines without the [pid][error kind] prefix in the logs if printed as-is *)
Exn.backtrace () |> String.split ~on:'\n'
|> List.iter ~f:(fun line -> log_of_kind error "%s@\n" line) ;
log_of_kind error "%s@\n" s ;
die error "%s" s)
msg
(* create new channel from the log file, and dumps the contents of the temporary log buffer there *) (* create new channel from the log file, and dumps the contents of the temporary log buffer there *)
let setup_log_file () = let setup_log_file () =
@ -285,7 +275,7 @@ let setup_log_file () =
| _, `Channel _ | _, `Channel _
-> (* already set up *) -> (* already set up *)
() ()
| _, `Buffer b | _, `Console
-> let fmt, chan, preexisting_logfile = -> let fmt, chan, preexisting_logfile =
(* assumes Config.results_dir exists already *) (* assumes Config.results_dir exists already *)
let logfile_path = Config.results_dir ^/ Config.log_file in let logfile_path = Config.results_dir ^/ Config.log_file in
@ -300,7 +290,9 @@ let setup_log_file () =
log_file := (fmt, `Channel chan) ; log_file := (fmt, `Channel chan) ;
if preexisting_logfile then is_newline := false ; if preexisting_logfile then is_newline := false ;
reset_formatters () ; reset_formatters () ;
Buffer.output_buffer chan b if CLOpt.is_originator && preexisting_logfile then
phase
"============================================================@\n= New infer execution begins@\n============================================================"
(** type of printable elements *) (** type of printable elements *)
type print_type = type print_type =
@ -349,7 +341,7 @@ type print_action = print_type * Obj.t (** data to be printed *)
let delayed_actions = ref [] let delayed_actions = ref []
(** hook for the current printer of delayed print actions *) (** hook for the current printer of delayed print actions *)
let printer_hook = ref (fun _ -> failwith "uninitialized printer hook") let printer_hook = ref (fun _ -> SimpleLogging.(die InternalError) "uninitialized printer hook")
(** extend the current print log *) (** extend the current print log *)
let add_print_action pact = let add_print_action pact =

@ -14,6 +14,11 @@ open! IStd
module F = Format module F = Format
(* If Logging has not been set up yet, SimpleLogging can be used instead. Prefer to use the
functions here, as they can do more logging. *)
include module type of SimpleLogging
val environment_info : ('a, F.formatter, unit) format -> 'a val environment_info : ('a, F.formatter, unit) format -> 'a
(** log information about the environment *) (** log information about the environment *)
@ -58,15 +63,6 @@ type debug_level =
val debug : debug_kind -> debug_level -> ('a, F.formatter, unit) format -> 'a val debug : debug_kind -> debug_level -> ('a, F.formatter, unit) format -> 'a
(** log debug info *) (** log debug info *)
(** kind of error for [die], with similar semantics as above *)
type error = UserError | ExternalError | InternalError
val die : error -> ('a, F.formatter, unit, _) format4 -> 'a
(** Print message and exit. The error code depends on [error].
Do not use lightly: failing hard should not be considered unless it's impossible to keep
going. *)
(** Type of location in ml source: __POS__ *) (** Type of location in ml source: __POS__ *)
type ml_loc = string * int * int * int type ml_loc = string * int * int * int

@ -0,0 +1,41 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open! IStd
module F = Format
type error = ExternalError | InternalError | UserError
exception InferExternalError of string * string
exception InferInternalError of string * string
exception InferUserError of string * string
let raise_error error msg backtrace =
match error with
| ExternalError
-> raise (InferExternalError (msg, backtrace))
| InternalError
-> raise (InferInternalError (msg, backtrace))
| UserError
-> raise (InferUserError (msg, backtrace))
let die error msg =
let backtrace = Exn.backtrace () in
F.kasprintf (fun s -> raise_error error s backtrace) msg
let exit_code_of_exception = function
| InferUserError _
-> 1
| InferExternalError _
-> 3
| InferInternalError _
-> 4
| _
-> (* exit code 2 is used by the OCaml runtime in cases of uncaught exceptions *) 2

@ -0,0 +1,26 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open! IStd
(* WARNING: ONLY USE IF Logging IS NOT AVAILABLE TO YOU FOR SOME REASON (e.g., inside Config). *)
exception InferExternalError of string * string
exception InferInternalError of string * string
exception InferUserError of string * string
(** kind of error for [die], with similar semantics as [Logging.{external,internal,user}_error] *)
type error = ExternalError | InternalError | UserError
val exit_code_of_exception : Exn.t -> int
val die : error -> ('a, Format.formatter, unit, _) format4 -> 'a
(** Raise the corresponding exception. *)

@ -39,7 +39,7 @@ module Set = Caml.Set.Make (OrderedSourceFile)
let from_abs_path ?(warn_on_error= true) fname = let from_abs_path ?(warn_on_error= true) fname =
if Filename.is_relative fname then if Filename.is_relative fname then
failwithf "ERROR: Path %s is relative, when absolute path was expected .@." fname ; L.(die InternalError) "Path '%s' is relative, when absolute path was expected." fname ;
(* try to get realpath of source file. Use original if it fails *) (* try to get realpath of source file. Use original if it fails *)
let fname_real = let fname_real =
try Utils.realpath ~warn_on_error fname try Utils.realpath ~warn_on_error fname
@ -74,7 +74,7 @@ let pp fmt fname = Format.fprintf fmt "%s" (to_string fname)
let to_abs_path fname = let to_abs_path fname =
match fname with match fname with
| Invalid origin | Invalid origin
-> invalid_arg ("cannot be called with Invalid source file originating in " ^ origin) -> L.(die InternalError) "cannot be called with Invalid source file originating in %s" origin
| RelativeProjectRoot path | RelativeProjectRoot path
-> Filename.concat Config.project_root path -> Filename.concat Config.project_root path
| RelativeInferModel path | RelativeInferModel path
@ -96,7 +96,7 @@ let is_invalid = function Invalid _ -> true | _ -> false
let is_infer_model source_file = let is_infer_model source_file =
match source_file with match source_file with
| Invalid origin | Invalid origin
-> invalid_arg ("cannot be called with Invalid source file from " ^ origin) -> L.(die InternalError) "cannot be called with Invalid source file from %s" origin
| RelativeProjectRoot _ | Absolute _ | RelativeProjectRoot _ | Absolute _
-> false -> false
| RelativeInferModel _ | RelativeInferModel _
@ -112,7 +112,7 @@ let is_cpp_model file =
let is_under_project_root = function let is_under_project_root = function
| Invalid origin | Invalid origin
-> invalid_arg ("cannot be called with Invalid source file from " ^ origin) -> L.(die InternalError) "cannot be called with Invalid source file from %s" origin
| RelativeProjectRoot _ | RelativeProjectRoot _
-> true -> true
| Absolute _ | RelativeInferModel _ | Absolute _ | RelativeInferModel _

@ -11,6 +11,7 @@ open! IStd
open! PVariant open! PVariant
module F = Format module F = Format
module Hashtbl = Caml.Hashtbl module Hashtbl = Caml.Hashtbl
module L = SimpleLogging
(** initial process times *) (** initial process times *)
let initial_times = Unix.times () let initial_times = Unix.times ()
@ -211,7 +212,7 @@ let shell_escape_command cmd =
let create_dir dir = let create_dir dir =
try try
if (Unix.stat dir).Unix.st_kind <> Unix.S_DIR then if (Unix.stat dir).Unix.st_kind <> Unix.S_DIR then
failwithf "file %s exists and is not a directory@." dir L.(die ExternalError) "file '%s' already exists and is not a directory" dir
with Unix.Unix_error _ -> with Unix.Unix_error _ ->
try Unix.mkdir dir ~perm:0o700 try Unix.mkdir dir ~perm:0o700
with Unix.Unix_error _ -> with Unix.Unix_error _ ->
@ -220,7 +221,7 @@ let create_dir dir =
try Polymorphic_compare.( = ) (Unix.stat dir).Unix.st_kind Unix.S_DIR try Polymorphic_compare.( = ) (Unix.stat dir).Unix.st_kind Unix.S_DIR
with Unix.Unix_error _ -> false with Unix.Unix_error _ -> false
in in
if not created_concurrently then failwithf "cannot create directory %s@." dir if not created_concurrently then L.(die ExternalError) "cannot create directory '%s'" dir
let realpath_cache = Hashtbl.create 1023 let realpath_cache = Hashtbl.create 1023

@ -109,9 +109,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
mem |> Dom.Mem.add_stack (Loc.of_pvar array_pvar) v mem |> Dom.Mem.add_stack (Loc.of_pvar array_pvar) v
|> set_uninitialized node typ (Dom.Val.get_array_locs v) |> set_uninitialized node typ (Dom.Val.get_array_locs v)
| [_; _] | [_; _]
-> failwithf "Unexpected type of arguments for __set_array_length()" -> L.(die InternalError) "Unexpected type of arguments for __set_array_length()"
| _ | _
-> failwithf "Unexpected number of arguments for __set_array_length()" -> L.(die InternalError) "Unexpected number of arguments for __set_array_length()"
let handle_unknown_call let handle_unknown_call
: Typ.Procname.t -> (Ident.t * Typ.t) option -> Typ.Procname.t -> (Exp.t * Typ.t) list : Typ.Procname.t -> (Ident.t * Typ.t) option -> Typ.Procname.t -> (Exp.t * Typ.t) list

@ -370,14 +370,14 @@ module Bound = struct
let widen_l : t -> t -> t = let widen_l : t -> t -> t =
fun x y -> fun x y ->
assert (x <> Bot && y <> Bot) ; assert (x <> Bot && y <> Bot) ;
if equal x PInf || equal y PInf then failwith "Lower bound cannot be +oo." if equal x PInf || equal y PInf then L.(die InternalError) "Lower bound cannot be +oo."
else if le x y then x else if le x y then x
else MInf else MInf
let widen_u : t -> t -> t = let widen_u : t -> t -> t =
fun x y -> fun x y ->
assert (x <> Bot && y <> Bot) ; assert (x <> Bot && y <> Bot) ;
if equal x MInf || equal y MInf then failwith "Upper bound cannot be -oo." if equal x MInf || equal y MInf then L.(die InternalError) "Upper bound cannot be -oo."
else if le y x then x else if le y x then x
else PInf else PInf
@ -852,14 +852,14 @@ let top : t = NonBottom ItvPure.top
let lb : t -> Bound.t = function let lb : t -> Bound.t = function
| NonBottom x | NonBottom x
-> ItvPure.lb x -> ItvPure.lb x
| _ | Bottom
-> raise (Failure "lower bound of bottom") -> L.(die InternalError) "lower bound of bottom"
let ub : t -> Bound.t = function let ub : t -> Bound.t = function
| NonBottom x | NonBottom x
-> ItvPure.ub x -> ItvPure.ub x
| _ | Bottom
-> raise (Failure "upper bound of bottom") -> L.(die InternalError) "upper bound of bottom"
let of_int : int -> astate = fun n -> NonBottom (ItvPure.of_int n) let of_int : int -> astate = fun n -> NonBottom (ItvPure.of_int n)

@ -112,7 +112,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Typ.Procname.C _ | Typ.Procname.C _
-> true (* Needed for test code. *) -> true (* Needed for test code. *)
| Typ.Procname.Block _ | Typ.Procname.Linters_dummy_method | Typ.Procname.Block _ | Typ.Procname.Linters_dummy_method
-> failwith "Proc type not supported by crashcontext: block" -> L.(die InternalError) "Proc type not supported by crashcontext: block"
in in
String.equal frame.Stacktrace.method_str (Typ.Procname.get_method caller) String.equal frame.Stacktrace.method_str (Typ.Procname.get_method caller)
&& matches_class caller && matches_class caller
@ -166,7 +166,7 @@ let loaded_stacktraces =
let checker {Callbacks.proc_desc; tenv; get_proc_desc; summary} : Specs.summary = let checker {Callbacks.proc_desc; tenv; get_proc_desc; summary} : Specs.summary =
( match loaded_stacktraces with ( match loaded_stacktraces with
| None | None
-> failwith -> L.(die UserError)
"Missing command line option. Either '--stacktrace stack.json' or '--stacktrace-dir ./dir' must be used when running '-a crashcontext'. This options expects a JSON formated stack trace or a directory containing multiple such traces, respectively. See tests/codetoanalyze/java/crashcontext/*.json for examples of the expected format." "Missing command line option. Either '--stacktrace stack.json' or '--stacktrace-dir ./dir' must be used when running '-a crashcontext'. This options expects a JSON formated stack trace or a directory containing multiple such traces, respectively. See tests/codetoanalyze/java/crashcontext/*.json for examples of the expected format."
| Some stacktraces | Some stacktraces
-> let extras = {get_proc_desc; stacktraces} in -> let extras = {get_proc_desc; stacktraces} in

@ -9,6 +9,7 @@
open! IStd open! IStd
module IdMap = Var.Map module IdMap = Var.Map
module L = Logging
type astate = AccessPath.t IdMap.t type astate = AccessPath.t IdMap.t
@ -22,7 +23,8 @@ let check_invariant ap1 ap2 = function
() ()
| id | id
-> if not (AccessPath.equal ap1 ap2) then -> if not (AccessPath.equal ap1 ap2) then
failwithf "Id %a maps to both %a and %a@." Var.pp id AccessPath.pp ap1 AccessPath.pp ap2 L.(die InternalError)
"Id %a maps to both %a and %a" Var.pp id AccessPath.pp ap1 AccessPath.pp ap2
let ( <= ) ~lhs ~rhs = let ( <= ) ~lhs ~rhs =
if phys_equal lhs rhs then true if phys_equal lhs rhs then true

@ -181,4 +181,4 @@ let checker {Callbacks.summary; proc_desc; tenv} =
| Some (post, _) | Some (post, _)
-> report post proc_data ; summary -> report post proc_data ; summary
| None | None
-> failwithf "Analyzer failed to compute post for %a" Typ.Procname.pp proc_name -> L.(die InternalError) "Analyzer failed to compute post for %a" Typ.Procname.pp proc_name

@ -56,9 +56,8 @@ module Make (Spec : Spec) : S = struct
let iters_befor_timeout = 1000 in let iters_befor_timeout = 1000 in
(* failsafe for accidental non-finite height domains *) (* failsafe for accidental non-finite height domains *)
if num_iters >= iters_befor_timeout then if num_iters >= iters_befor_timeout then
failwith L.(die InternalError)
( "Stopping analysis after 1000 iterations without convergence." "Stopping analysis after 1000 iterations without convergence. Make sure your domain is finite height."
^ "Make sure your domain is finite height." )
else widen ~prev ~next ~num_iters else widen ~prev ~next ~num_iters
end end

@ -80,7 +80,7 @@ module Make (TraceElem : TraceElem.S) = struct
| [report] | [report]
-> Some report -> Some report
| _ | _
-> failwithf "Should not get >1 report for 1 sink" -> L.(die InternalError) "Should not get >1 report for 1 sink"
let pp fmt t = let pp fmt t =
let pp_passthroughs_if_not_empty fmt p = let pp_passthroughs_if_not_empty fmt p =

@ -184,7 +184,7 @@ let is_foreign tu_opt (v, _) =
| TUExtern, Some _ | TUExtern, Some _
-> true -> true
| _, None | _, None
-> invalid_arg "cannot be called with translation unit set to None" -> L.(die InternalError) "cannot be called with translation unit set to None"
let report_siof summary trace pdesc gname loc = let report_siof summary trace pdesc gname loc =
let tu_opt = let tu_opt =

@ -11,6 +11,7 @@
open! IStd open! IStd
module F = Format module F = Format
module L = Logging
type frame = {class_str: string; method_str: string; file_str: string; line_num: int option} type frame = {class_str: string; method_str: string; file_str: string; line_num: int option}
@ -86,7 +87,7 @@ let of_string s =
let parsed = List.map ~f:parse_stack_frame trace in let parsed = List.map ~f:parse_stack_frame trace in
make exception_name parsed make exception_name parsed
| [] | []
-> failwith "Empty stack trace" -> L.(die UserError) "Empty stack trace"
let of_json filename json = let of_json filename json =
let exception_name_key = "exception_type" in let exception_name_key = "exception_type" in
@ -94,7 +95,7 @@ let of_json filename json =
let extract_json_member key = let extract_json_member key =
match Yojson.Basic.Util.member key json with match Yojson.Basic.Util.member key json with
| `Null | `Null
-> failwithf "Missing key in supplied JSON data: %s (in file %s)" key filename -> L.(die UserError) "Missing key in supplied JSON data: %s (in file %s)" key filename
| item | item
-> item -> item
in in
@ -109,4 +110,5 @@ let of_json filename json =
let of_json_file filename = let of_json_file filename =
try of_json filename (Yojson.Basic.from_file filename) try of_json filename (Yojson.Basic.from_file filename)
with Sys_error msg | Yojson.Json_error msg -> with Sys_error msg | Yojson.Json_error msg ->
failwithf "Could not read or parse the supplied JSON stacktrace file %s :@\n %s" filename msg L.(die UserError)
"Could not read or parse the supplied JSON stacktrace file %s :@\n %s" filename msg

@ -26,7 +26,7 @@ let make_excluder locks threads =
if locks && not threads then ThreadSafetyDomain.Excluder.Lock if locks && not threads then ThreadSafetyDomain.Excluder.Lock
else if not locks && threads then ThreadSafetyDomain.Excluder.Thread else if not locks && threads then ThreadSafetyDomain.Excluder.Thread
else if locks && threads then ThreadSafetyDomain.Excluder.Both else if locks && threads then ThreadSafetyDomain.Excluder.Both
else failwithf "called when neither lock nor thread known" else L.(die InternalError) "called when neither lock nor thread known"
module TransferFunctions (CFG : ProcCfg.S) = struct module TransferFunctions (CFG : ProcCfg.S) = struct
module CFG = CFG module CFG = CFG
@ -513,8 +513,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Some HilExp.AccessPath receiver_ap | Some HilExp.AccessPath receiver_ap
-> receiver_ap -> receiver_ap
| _ | _
-> failwithf "Call to %a is marked as a container write, but has no receiver" -> L.(die InternalError)
Typ.Procname.pp callee_pname "Call to %a is marked as a container write, but has no receiver" Typ.Procname.pp
callee_pname
in in
match get_container_access callee_pname tenv with match get_container_access callee_pname tenv with
| Some ContainerWrite | Some ContainerWrite
@ -599,7 +600,8 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
in in
{astate with attribute_map} {astate with attribute_map}
| None | None
-> failwithf "Procedure %a specified as returning boolean, but returns nothing" -> L.(die InternalError)
"Procedure %a specified as returning boolean, but returns nothing"
Typ.Procname.pp callee_pname ) Typ.Procname.pp callee_pname )
| Unknown | Unknown
-> astate -> astate
@ -622,7 +624,8 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
in in
{astate with attribute_map} {astate with attribute_map}
| None | None
-> failwithf "Procedure %a specified as returning boolean, but returns nothing" -> L.(die InternalError)
"Procedure %a specified as returning boolean, but returns nothing"
Typ.Procname.pp callee_pname ) Typ.Procname.pp callee_pname )
| NoEffect -> | NoEffect ->
match get_summary pdesc callee_pname actuals loc tenv with match get_summary pdesc callee_pname actuals loc tenv with
@ -872,7 +875,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Call (_, Indirect _, _, _, _) -> | Call (_, Indirect _, _, _, _) ->
match Procdesc.get_proc_name pdesc with match Procdesc.get_proc_name pdesc with
| Typ.Procname.Java _ | Typ.Procname.Java _
-> failwithf "Unexpected indirect call instruction %a" HilInstr.pp instr -> L.(die InternalError) "Unexpected indirect call instruction %a" HilInstr.pp instr
| _ | _
-> astate -> astate
end end
@ -1545,7 +1548,7 @@ let quotient_access_map acc_map =
-> ThreadSafetyDomain.Access.equal k k') -> ThreadSafetyDomain.Access.equal k k')
m m
in in
if AccessListMap.is_empty k_part then failwith "may_alias is not reflexive!" ; if AccessListMap.is_empty k_part then L.(die InternalError) "may_alias is not reflexive!" ;
let k_accesses = AccessListMap.fold (fun _ v acc' -> List.append v acc') k_part [] in let k_accesses = AccessListMap.fold (fun _ v acc' -> List.append v acc') k_part [] in
let new_acc = AccessListMap.add k k_accesses acc in let new_acc = AccessListMap.add k k_accesses acc in
aux new_acc non_k_part aux new_acc non_k_part

@ -9,11 +9,13 @@
open! IStd open! IStd
module F = Format module F = Format
module L = Logging
module AnnotationAliases = struct module AnnotationAliases = struct
let of_json = function let of_json = function
| `List aliases | `List aliases
-> List.map ~f:Yojson.Basic.Util.to_string aliases -> List.map ~f:Yojson.Basic.Util.to_string aliases
| _ | _
-> failwith "Couldn't parse thread-safety annotation aliases; expected list of strings" -> L.(die UserError)
"Couldn't parse thread-safety annotation aliases; expected list of strings"
end end

@ -247,7 +247,6 @@ module AnnotationSpec = struct
(* The default sanitizer does not sanitize anything *) (* The default sanitizer does not sanitize anything *)
let default_sanitizer _ _ = false let default_sanitizer _ _ = false
end end
module StandardAnnotationSpec = struct module StandardAnnotationSpec = struct
@ -427,7 +426,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Sil.Prune (exp, _, _, _) when prunes_tracking_var astate exp | Sil.Prune (exp, _, _, _) when prunes_tracking_var astate exp
-> Domain.stop_tracking astate -> Domain.stop_tracking astate
| Sil.Call (None, _, _, _, _) | Sil.Call (None, _, _, _, _)
-> failwith "Expecting a return identifier" -> L.(die InternalError) "Expecting a return identifier"
| _ | _
-> astate -> astate
end end

@ -149,7 +149,7 @@ let check_printf_args_ok tenv (node: Procdesc.Node.t) (instr: Sil.instr)
| Exp.Const c | Exp.Const c
-> PatternMatch.java_get_const_type_name c -> PatternMatch.java_get_const_type_name c
| _ | _
-> raise (Failure "Could not resolve fixed type name") -> L.(die InternalError) "Could not resolve fixed type name"
in in
match instr with match instr with
| Sil.Call (_, Exp.Const Const.Cfun pn, args, cl, _) -> ( | Sil.Call (_, Exp.Const Const.Cfun pn, args, cl, _) -> (

@ -8,6 +8,7 @@
*) *)
open! IStd open! IStd
module L = Logging
type t = Clang_ast_t.pointer type t = Clang_ast_t.pointer
@ -34,8 +35,8 @@ let visit_ast ?(visit_decl= empty_v) ?(visit_stmt= empty_v) ?(visit_type= empty_
| None | None
-> () -> ()
| Some error | Some error
-> failwithf "visiting the clang AST failed with error %s" -> L.(die InternalError)
(Ag_util.Validation.string_of_error error) "visiting the clang AST failed with error %s" (Ag_util.Validation.string_of_error error)
let get_ptr_from_node node = let get_ptr_from_node node =
match node with match node with

@ -85,7 +85,7 @@ let normalize ~prog ~args : action_item list =
| prog :: args | prog :: args
-> ClangCommand.mk ClangQuotes.EscapedDoubleQuotes ~prog ~args -> ClangCommand.mk ClangQuotes.EscapedDoubleQuotes ~prog ~args
| [] | []
-> failwith "ClangWrapper: argv cannot be empty" ) -> L.(die InternalError) "ClangWrapper: argv cannot be empty" )
else if Str.string_match (Str.regexp "clang[^ :]*: warning: ") line 0 then ClangWarning line else if Str.string_match (Str.regexp "clang[^ :]*: warning: ") line 0 then ClangWarning line
else ClangError line else ClangError line
in in
@ -112,7 +112,7 @@ let exec_action_item = function
| ClangError error | ClangError error
-> (* An error in the output of `clang -### ...`. Outputs the error and fail. This is because -> (* An error in the output of `clang -### ...`. Outputs the error and fail. This is because
`clang -###` pretty much never fails, but warns of failures on stderr instead. *) `clang -###` pretty much never fails, but warns of failures on stderr instead. *)
failwithf L.(die UserError)
"Failed to execute compilation command. Output:@\n%s@\n*** Infer needs a working compilation command to run." "Failed to execute compilation command. Output:@\n%s@\n*** Infer needs a working compilation command to run."
error error
| ClangWarning warning | ClangWarning warning

@ -338,7 +338,7 @@ let rec is_objc_if_descendant ?(blacklist= default_blacklist) if_decl ancestors
(* List of ancestors to check for and list of classes to short-circuit to (* List of ancestors to check for and list of classes to short-circuit to
false can't intersect *) false can't intersect *)
if not String.Set.(is_empty (inter (of_list blacklist) (of_list ancestors))) then if not String.Set.(is_empty (inter (of_list blacklist) (of_list ancestors))) then
failwith "Blacklist and ancestors must be mutually exclusive." L.(die InternalError) "Blacklist and ancestors must be mutually exclusive."
else else
match if_decl with match if_decl with
| Some Clang_ast_t.ObjCInterfaceDecl (_, ndi, _, _, _) | Some Clang_ast_t.ObjCInterfaceDecl (_, ndi, _, _, _)

@ -8,6 +8,7 @@
*) *)
open! IStd open! IStd
module L = Logging
(* Helper functions *) (* Helper functions *)
let location_from_stmt lctx stmt = let location_from_stmt lctx stmt =
@ -45,9 +46,9 @@ let decl_ref_or_selector_name an =
| [(Ctl_parser_types.Decl _ as decl_an)] | [(Ctl_parser_types.Decl _ as decl_an)]
-> "The reference " ^ Ctl_parser_types.ast_node_name decl_an -> "The reference " ^ Ctl_parser_types.ast_node_name decl_an
| _ | _
-> failwith -> L.(die ExternalError)
( "decl_ref_or_selector_name must be called with a DeclRefExpr or an ObjCMessageExpr, but got " "decl_ref_or_selector_name must be called with a DeclRefExpr or an ObjCMessageExpr, but got %s"
^ tag_name_of_node an ) (tag_name_of_node an)
let iphoneos_target_sdk_version _ = let iphoneos_target_sdk_version _ =
match Config.iphoneos_target_sdk_version with Some f -> f | None -> "0" match Config.iphoneos_target_sdk_version with Some f -> f | None -> "0"
@ -62,9 +63,9 @@ let available_ios_sdk an =
| None | None
-> "" ) -> "" )
| _ | _
-> failwith -> L.(die ExternalError)
( "available_ios_sdk must be called with a DeclRefExpr or an ObjCMessageExpr, but got " "available_ios_sdk must be called with a DeclRefExpr or an ObjCMessageExpr, but got %s"
^ tag_name_of_node an ) (tag_name_of_node an)
let class_available_ios_sdk an = let class_available_ios_sdk an =
match CPredicates.receiver_method_call an with match CPredicates.receiver_method_call an with
@ -75,17 +76,18 @@ let class_available_ios_sdk an =
| None | None
-> "" ) -> "" )
| None | None
-> failwith -> L.(die ExternalError)
( "class_available_ios_sdk must be called with ObjCMessageExpr, but got " "class_available_ios_sdk must be called with ObjCMessageExpr, but got %s"
^ tag_name_of_node an ) (tag_name_of_node an)
let receiver_method_call an = let receiver_method_call an =
match CPredicates.receiver_method_call an with match CPredicates.receiver_method_call an with
| Some decl | Some decl
-> Ctl_parser_types.ast_node_name (Ctl_parser_types.Decl decl) -> Ctl_parser_types.ast_node_name (Ctl_parser_types.Decl decl)
| _ | _
-> failwith -> L.(die ExternalError)
("receiver_method_call must be called with ObjCMessageExpr, but got " ^ tag_name_of_node an) "receiver_method_call must be called with ObjCMessageExpr, but got %s"
(tag_name_of_node an)
let ivar_name an = let ivar_name an =
let open Clang_ast_t in let open Clang_ast_t in

@ -14,7 +14,7 @@ let already_imported_files = ref []
let rec parse_import_file import_file channel = let rec parse_import_file import_file channel =
if List.mem ~equal:String.equal !already_imported_files import_file then if List.mem ~equal:String.equal !already_imported_files import_file then
failwith ("Cyclic imports: file '" ^ import_file ^ "' was already imported.") L.(die ExternalError) "Cyclic imports: file '%s' was already imported." import_file
else else
match CTLParserHelper.parse_al_file import_file channel with match CTLParserHelper.parse_al_file import_file channel with
| Some | Some

@ -24,7 +24,7 @@ let filter_parsed_linters_developer parsed_linters =
if List.length parsed_linters > 1 && Config.linters_developer_mode then if List.length parsed_linters > 1 && Config.linters_developer_mode then
match Config.linter with match Config.linter with
| None | None
-> failwith -> L.(die UserError)
"In linters developer mode you should debug only one linter at a time. This is important for debugging the rule. Pass the flag --linter <name> to specify the linter you want to debug." "In linters developer mode you should debug only one linter at a time. This is important for debugging the rule. Pass the flag --linter <name> to specify the linter you want to debug."
| Some lint | Some lint
-> List.filter ~f:(fun (rule: linter) -> String.equal rule.issue_desc.id lint) parsed_linters -> List.filter ~f:(fun (rule: linter) -> String.equal rule.issue_desc.id lint) parsed_linters
@ -266,7 +266,7 @@ let rec apply_substitution f sub =
let expand_formula phi _map _error_msg = let expand_formula phi _map _error_msg =
let fail_with_circular_macro_definition name error_msg = let fail_with_circular_macro_definition name error_msg =
failwithf "Macro '%s' has a circular definition.@\n Cycle:@\n%s" name error_msg L.(die ExternalError) "Macro '%s' has a circular definition.@\n Cycle:@\n%s" name error_msg
in in
let open CTL in let open CTL in
let rec expand acc map error_msg = let rec expand acc map error_msg =
@ -289,9 +289,8 @@ let expand_formula phi _map _error_msg =
let map' = ALVar.FormulaIdMap.add av (true, fparams, f1) map in let map' = ALVar.FormulaIdMap.add av (true, fparams, f1) map in
expand f1_sub map' error_msg' expand f1_sub map' error_msg'
| None | None
-> failwith -> L.(die ExternalError)
( "Formula identifier '" ^ name "Formula identifier '%s' is not called with the right number of parameters" name
^ "' is not called with the right number of parameters" )
with Not_found -> acc with Not_found -> acc
(* in this case it should be a predicate *) ) (* in this case it should be a predicate *) )
| Not f1 | Not f1
@ -337,7 +336,7 @@ let rec expand_path paths path_map =
try try
let paths = ALVar.VarMap.find path_var path_map in let paths = ALVar.VarMap.find path_var path_map in
List.append paths (expand_path rest path_map) List.append paths (expand_path rest path_map)
with Not_found -> failwithf "Path variable %s not found. " path_var ) with Not_found -> L.(die ExternalError) "Path variable %s not found. " path_var )
| path :: rest | path :: rest
-> path :: expand_path rest path_map -> path :: expand_path rest path_map
@ -348,8 +347,8 @@ let _build_macros_map macros init_map =
match data with match data with
| CTL.CLet (key, params, formula) | CTL.CLet (key, params, formula)
-> if ALVar.FormulaIdMap.mem key map' then -> if ALVar.FormulaIdMap.mem key map' then
failwith L.(die ExternalError)
("Macro '" ^ ALVar.formula_id_to_string key ^ "' has more than one definition.") "Macro '%s' has more than one definition." (ALVar.formula_id_to_string key)
else ALVar.FormulaIdMap.add key (false, params, formula) map' else ALVar.FormulaIdMap.add key (false, params, formula) map'
| _ | _
-> map') -> map')
@ -369,7 +368,7 @@ let build_paths_map paths =
match data match data
with path_name, paths -> with path_name, paths ->
if ALVar.VarMap.mem path_name map' then if ALVar.VarMap.mem path_name map' then
failwith ("Path '" ^ path_name ^ "' has more than one definition.") L.(die ExternalError) "Path '%s' has more than one definition." path_name
else ALVar.VarMap.add path_name paths map') else ALVar.VarMap.add path_name paths map')
~init:init_map paths ~init:init_map paths
in in

@ -415,7 +415,7 @@ let captures_cxx_references an = List.length (captured_variables_cxx_ref an) > 0
let is_binop_with_kind an alexp_kind = let is_binop_with_kind an alexp_kind =
let str_kind = ALVar.alexp_to_string alexp_kind in let str_kind = ALVar.alexp_to_string alexp_kind in
if not (Clang_ast_proj.is_valid_binop_kind_name str_kind) then if not (Clang_ast_proj.is_valid_binop_kind_name str_kind) then
failwith ("Binary operator kind " ^ str_kind ^ " is not valid") ; L.(die ExternalError) "Binary operator kind '%s' is not valid" str_kind ;
match an with match an with
| Ctl_parser_types.Stmt Clang_ast_t.BinaryOperator (_, _, _, boi) | Ctl_parser_types.Stmt Clang_ast_t.BinaryOperator (_, _, _, boi)
-> ALVar.compare_str_with_alexp (Clang_ast_proj.string_of_binop_kind boi.boi_kind) alexp_kind -> ALVar.compare_str_with_alexp (Clang_ast_proj.string_of_binop_kind boi.boi_kind) alexp_kind
@ -425,7 +425,7 @@ let is_binop_with_kind an alexp_kind =
let is_unop_with_kind an alexp_kind = let is_unop_with_kind an alexp_kind =
let str_kind = ALVar.alexp_to_string alexp_kind in let str_kind = ALVar.alexp_to_string alexp_kind in
if not (Clang_ast_proj.is_valid_unop_kind_name str_kind) then if not (Clang_ast_proj.is_valid_unop_kind_name str_kind) then
failwith ("Unary operator kind " ^ str_kind ^ " is not valid") ; L.(die ExternalError) "Unary operator kind '%s' is not valid" str_kind ;
match an with match an with
| Ctl_parser_types.Stmt Clang_ast_t.UnaryOperator (_, _, _, uoi) | Ctl_parser_types.Stmt Clang_ast_t.UnaryOperator (_, _, _, uoi)
-> ALVar.compare_str_with_alexp (Clang_ast_proj.string_of_unop_kind uoi.uoi_kind) alexp_kind -> ALVar.compare_str_with_alexp (Clang_ast_proj.string_of_unop_kind uoi.uoi_kind) alexp_kind
@ -448,7 +448,7 @@ let has_cast_kind an alexp_kind =
let is_node an nodename = let is_node an nodename =
let nodename_str = ALVar.alexp_to_string nodename in let nodename_str = ALVar.alexp_to_string nodename in
if not (Clang_ast_proj.is_valid_astnode_kind nodename_str) then if not (Clang_ast_proj.is_valid_astnode_kind nodename_str) then
failwith ("Node " ^ nodename_str ^ " is not a valid AST node") ; L.(die ExternalError) "Node '%s' is not a valid AST node" nodename_str ;
let an_str = let an_str =
match an with match an with
| Ctl_parser_types.Stmt s | Ctl_parser_types.Stmt s

@ -433,7 +433,7 @@ module Debug = struct
| Eval_false | Eval_false
-> "red" -> "red"
| _ | _
-> failwith "Tree is not fully evaluated" -> L.(die InternalError) "Tree is not fully evaluated"
in in
let label = let label =
let string_of_lcxt c = let string_of_lcxt c =
@ -527,7 +527,7 @@ let create_ctl_evaluation_tracker source_file =
| true, None | true, None
-> ctl_evaluation_tracker := Some (Debug.EvaluationTracker.create source_file) -> ctl_evaluation_tracker := Some (Debug.EvaluationTracker.create source_file)
| true, _ | true, _
-> failwith "A CTL evaluation tracker has already been created" -> L.(die InternalError) "A CTL evaluation tracker has already been created"
| _ | _
-> () -> ()
@ -853,7 +853,7 @@ let rec eval_Atomic _pred_name args an lcxt =
| "within_available_class_block", [], an | "within_available_class_block", [], an
-> CPredicates.within_available_class_block lcxt an -> CPredicates.within_available_class_block lcxt an
| _ | _
-> failwith ("ERROR: Undefined Predicate or wrong set of arguments: '" ^ pred_name ^ "'") -> L.(die ExternalError) "Undefined Predicate or wrong set of arguments: '%s'" pred_name
(* an, lcxt |= EF phi <=> (* an, lcxt |= EF phi <=>
an, lcxt |= phi or exists an' in Successors(st): an', lcxt |= EF phi an, lcxt |= phi or exists an' in Successors(st): an', lcxt |= EF phi

@ -213,7 +213,7 @@ and type_ptr_to_type_desc translate_decl tenv type_ptr : Typ.desc =
| Clang_ast_extend.ErrorType | Clang_ast_extend.ErrorType
-> Typ.Tvoid -> Typ.Tvoid
| _ | _
-> raise (invalid_arg "unknown variant for type_ptr") -> L.(die InternalError) "unknown variant for type_ptr"
and qual_type_to_sil_type translate_decl tenv qual_type = and qual_type_to_sil_type translate_decl tenv qual_type =
let desc = type_ptr_to_type_desc translate_decl tenv qual_type.Clang_ast_t.qt_type_ptr in let desc = type_ptr_to_type_desc translate_decl tenv qual_type.Clang_ast_t.qt_type_ptr in

@ -8,10 +8,11 @@
*) *)
open! IStd open! IStd
(* This module adds more variants to some types in AST The implementation extends default one from
the facebook-clang-plugins repository *)
module L = Logging
(* This module adds more variants to some types in AST *)
(* The implementation extends default one from *)
(* facebook-clang-plugins repository *)
(* Type pointers *) (* Type pointers *)
type Clang_ast_types.TypePtr.t += type Clang_ast_types.TypePtr.t +=
| Builtin of Clang_ast_t.builtin_type_kind | Builtin of Clang_ast_t.builtin_type_kind
@ -21,6 +22,24 @@ type Clang_ast_types.TypePtr.t +=
| DeclPtr of int | DeclPtr of int
| ErrorType | ErrorType
let rec type_ptr_to_string = function
| Clang_ast_types.TypePtr.Ptr raw
-> "clang_ptr_" ^ string_of_int raw
| Builtin t
-> "sil_" ^ Clang_ast_j.string_of_builtin_type_kind t
| PointerOf typ
-> "pointer_of_" ^ type_ptr_to_string typ.Clang_ast_t.qt_type_ptr
| ReferenceOf typ
-> "reference_of_" ^ type_ptr_to_string typ.Clang_ast_t.qt_type_ptr
| ClassType name
-> "class_name_" ^ Typ.Name.name name
| DeclPtr raw
-> "decl_ptr_" ^ string_of_int raw
| ErrorType
-> "error_type"
| _
-> "unknown"
module TypePointerOrd = struct module TypePointerOrd = struct
type t = Clang_ast_types.TypePtr.t type t = Clang_ast_types.TypePtr.t
@ -66,8 +85,9 @@ module TypePointerOrd = struct
-> -1 -> -1
| ErrorType, ErrorType | ErrorType, ErrorType
-> 0 -> 0
| _ | t1, t2
-> raise (invalid_arg "unexpected type_ptr variants: ") -> L.(die InternalError)
"unexpected type_ptr variants: %s, %s" (type_ptr_to_string t1) (type_ptr_to_string t2)
and compare_qual_type (qt1: Clang_ast_t.qual_type) (qt2: Clang_ast_t.qual_type) = and compare_qual_type (qt1: Clang_ast_t.qual_type) (qt2: Clang_ast_t.qual_type) =
if phys_equal qt1 qt2 then 0 if phys_equal qt1 qt2 then 0
@ -90,21 +110,3 @@ module TypePointerOrd = struct
end end
module TypePointerMap = Caml.Map.Make (TypePointerOrd) module TypePointerMap = Caml.Map.Make (TypePointerOrd)
let rec type_ptr_to_string = function
| Clang_ast_types.TypePtr.Ptr raw
-> "clang_ptr_" ^ string_of_int raw
| Builtin t
-> "sil_" ^ Clang_ast_j.string_of_builtin_type_kind t
| PointerOf typ
-> "pointer_of_" ^ type_ptr_to_string typ.Clang_ast_t.qt_type_ptr
| ReferenceOf typ
-> "reference_of_" ^ type_ptr_to_string typ.Clang_ast_t.qt_type_ptr
| ClassType name
-> "class_name_" ^ Typ.Name.name name
| DeclPtr raw
-> "decl_ptr_" ^ string_of_int raw
| ErrorType
-> "error_type"
| _
-> "unknown"

@ -172,8 +172,8 @@ clause:
{ L.(debug Linters Verbose) "\tParsed SET clause@\n"; { L.(debug Linters Verbose) "\tParsed SET clause@\n";
let alvar = match $2 with let alvar = match $2 with
| "report_when" -> ALVar.Report_when | "report_when" -> ALVar.Report_when
| _ -> failwith "string '%s' cannot be set to a variable. \ | _ -> L.(die ExternalError) "string '%s' cannot be set to a variable. \
Use the reserverd variable 'report_when'" in Use the reserved variable 'report_when'" $2 in
CTL.CSet (alvar, $4) } CTL.CSet (alvar, $4) }
| SET WHITELIST_PATH ASSIGNMENT LEFT_BRACE path_list RIGHT_BRACE | SET WHITELIST_PATH ASSIGNMENT LEFT_BRACE path_list RIGHT_BRACE
{ CTL.CPath (`WhitelistPath, $5) } { CTL.CPath (`WhitelistPath, $5) }
@ -188,9 +188,10 @@ clause:
| "mode" -> ALVar.Mode | "mode" -> ALVar.Mode
| "doc_url" -> ALVar.Doc_url | "doc_url" -> ALVar.Doc_url
| "name" -> ALVar.Name | "name" -> ALVar.Name
| _ -> failwithf "string '%s' cannot be set in a SET clause. \ | _ -> L.(die ExternalError)
Use either of: \ "string '%s' cannot be set in a SET clause. \
'doc_url', 'message', 'mode', 'name', 'severity' or 'suggestion'" $2 in Use either of: \
'doc_url', 'message', 'mode', 'name', 'severity' or 'suggestion'" $2 in
CTL.CDesc (alvar, $4) } CTL.CDesc (alvar, $4) }
| let_clause { $1 } | let_clause { $1 }
; ;

@ -213,8 +213,9 @@ let inhabit_call tenv (procname, receiver) cfg env =
| formals, None | formals, None
-> formals -> formals
| [], Some _ | [], Some _
-> failwithf "Expected at least one formal to bind receiver to in method %a" -> L.(die InternalError)
Typ.Procname.pp procname "Expected at least one formal to bind receiver to in method %a" Typ.Procname.pp
procname
in in
let args, env = inhabit_args tenv formals cfg env in let args, env = inhabit_args tenv formals cfg env in
inhabit_call_with_args procname procdesc args env inhabit_call_with_args procname procdesc args env

@ -8,6 +8,7 @@
*) *)
open! IStd open! IStd
module L = Logging
type target = {name: string; flavors: string list} type target = {name: string; flavors: string list}
@ -19,7 +20,7 @@ let target_of_string target =
| [name] | [name]
-> {name; flavors= []} -> {name; flavors= []}
| _ | _
-> failwithf "cannot parse target %s" target -> L.(die ExternalError) "cannot parse target %s" target
let string_of_target {name; flavors} = let string_of_target {name; flavors} =
let pp_string fmt s = Format.fprintf fmt "%s" s in let pp_string fmt s = Format.fprintf fmt "%s" s in
@ -49,7 +50,8 @@ let add_flavor_to_target target =
| None, (BiAbduction | CaptureOnly | Checkers | Linters) | None, (BiAbduction | CaptureOnly | Checkers | Linters)
-> add "infer-capture-all" -> add "infer-capture-all"
| None, Crashcontext | None, Crashcontext
-> failwithf "Analyzer %s is Java-only; not supported with Buck flavors" -> L.(die UserError)
"Analyzer %s is Java-only; not supported with Buck flavors"
(Config.string_of_analyzer Config.analyzer) (Config.string_of_analyzer Config.analyzer)
let add_flavors_to_buck_command build_cmd = let add_flavors_to_buck_command build_cmd =

@ -95,7 +95,8 @@ let get_compilation_database_files_buck ~prog ~args =
in in
match exit_or_signal with match exit_or_signal with
| Error _ as status | Error _ as status
-> failwithf "*** command failed:@\n*** %s@\n*** %s@." buck_targets_shell -> L.(die ExternalError)
"*** command failed:@\n*** %s@\n*** %s@." buck_targets_shell
(Unix.Exit_or_signal.to_string_hum status) (Unix.Exit_or_signal.to_string_hum status)
| Ok () -> | Ok () ->
match output with match output with
@ -111,8 +112,8 @@ let get_compilation_database_files_buck ~prog ~args =
| [_; filename] | [_; filename]
-> `Raw filename :: compilation_database_files -> `Raw filename :: compilation_database_files
| _ | _
-> failwithf "Failed to parse `buck targets --show-output ...` line of output:@\n%s" -> L.(die ExternalError)
line "Failed to parse `buck targets --show-output ...` line of output:@\n%s" line
in in
List.fold ~f:scan_output ~init:[] lines ) List.fold ~f:scan_output ~init:[] lines )
| _ | _

@ -58,6 +58,7 @@ let capture compiler ~prog ~args =
| Ok () | Ok ()
-> () -> ()
| Error _ as status | Error _ as status
-> failwithf "*** capture command failed:@\n*** %s@\n*** %s@." -> L.(die ExternalError)
"*** capture command failed:@\n*** %s@\n*** %s@."
(String.concat ~sep:" " (prog :: args)) (String.concat ~sep:" " (prog :: args))
(Unix.Exit_or_signal.to_string_hum status) (Unix.Exit_or_signal.to_string_hum status)

@ -49,7 +49,7 @@ let decode_json_file (database: t) json_format =
|> fst |> fst
in in
L.(debug Capture Quiet) "parsing compilation database from %s@\n" json_path ; L.(debug Capture Quiet) "parsing compilation database from %s@\n" json_path ;
let exit_format_error () = failwith "Json file doesn't have the expected format" in let exit_format_error () = L.(die ExternalError) "Json file doesn't have the expected format" in
let json = Yojson.Basic.from_file json_path in let json = Yojson.Basic.from_file json_path in
let get_dir el = match el with "directory", `String dir -> Some (to_string dir) | _ -> None in let get_dir el = match el with "directory", `String dir -> Some (to_string dir) | _ -> None in
let get_file el = match el with "file", `String file -> Some (to_string file) | _ -> None in let get_file el = match el with "file", `String file -> Some (to_string file) | _ -> None in

@ -59,7 +59,7 @@ let build_system_exe_assoc =
let build_system_of_exe_name name = let build_system_of_exe_name name =
try List.Assoc.find_exn ~equal:String.equal (List.Assoc.inverse build_system_exe_assoc) name try List.Assoc.find_exn ~equal:String.equal (List.Assoc.inverse build_system_exe_assoc) name
with Not_found -> invalid_argf "Unsupported build command %s" name with Not_found -> L.(die InternalError) "Unsupported build command %s" name
let string_of_build_system build_system = let string_of_build_system build_system =
List.Assoc.find_exn ~equal:equal_build_system build_system_exe_assoc build_system List.Assoc.find_exn ~equal:equal_build_system build_system_exe_assoc build_system
@ -474,7 +474,7 @@ let assert_supported_mode required_analyzer requested_mode_string =
| `Xcode | `Xcode
-> "clang and xcode" -> "clang and xcode"
in in
failwithf L.(die UserError)
"Unsupported build mode: %s@\nInfer was built with %s analyzers disabled.@ Please rebuild infer with %s enabled.@." "Unsupported build mode: %s@\nInfer was built with %s analyzers disabled.@ Please rebuild infer with %s enabled.@."
requested_mode_string analyzer_string analyzer_string requested_mode_string analyzer_string analyzer_string

@ -69,7 +69,7 @@ let compile compiler build_prog build_args =
-> L.(debug Capture Quiet) "*** Failed: %a!@\n" Exn.pp exn ; k () -> L.(debug Capture Quiet) "*** Failed: %a!@\n" Exn.pp exn ; k ()
| None, `UnixError (err, log) | None, `UnixError (err, log)
-> let verbose_errlog = Utils.with_file_in verbose_out_file ~f:In_channel.input_all in -> let verbose_errlog = Utils.with_file_in verbose_out_file ~f:In_channel.input_all in
failwithf L.(die UserError)
"@\n*** Failed to execute compilation command: %s@\n*** Command: %s@\n*** Output:@\n%s%s@\n*** Infer needs a working compilation command to run.@." "@\n*** Failed to execute compilation command: %s@\n*** Command: %s@\n*** Output:@\n%s%s@\n*** Infer needs a working compilation command to run.@."
(Unix.Exit_or_signal.to_string_hum (Error err)) shell_cmd log verbose_errlog (Unix.Exit_or_signal.to_string_hum (Error err)) shell_cmd log verbose_errlog
| None, `ExceptionError exn | None, `ExceptionError exn

@ -83,7 +83,7 @@ let add_infer_profile_to_xml dir maven_xml infer_xml =
-> (* closing the first tag, we're done *) -> (* closing the first tag, we're done *)
() ()
| [] | []
-> invalid_arg "ill-formed xml" ) -> L.(die UserError) "ill-formed xml" )
| `Data data | `Data data
-> Xmlm.output xml_out elt_in ; -> Xmlm.output xml_out elt_in ;
( match tag_stack with ( match tag_stack with
@ -110,7 +110,7 @@ let add_infer_profile_to_xml dir maven_xml infer_xml =
-> Xmlm.output infer_xml (`Dtd None) ) ; -> Xmlm.output infer_xml (`Dtd None) ) ;
process_root maven_xml infer_xml ; process_root maven_xml infer_xml ;
Xmlm.eoi maven_xml |> ignore ; Xmlm.eoi maven_xml |> ignore ;
if not (Xmlm.eoi maven_xml) then invalid_arg "More than one document" if not (Xmlm.eoi maven_xml) then L.(die UserError) "More than one document"
in in
process_document () process_document ()
@ -171,6 +171,7 @@ let capture ~prog ~args =
| Ok () | Ok ()
-> () -> ()
| Error _ as status | Error _ as status
-> failwithf "*** Maven command failed:@\n*** %s@\n*** %s@\n" -> L.(die UserError)
"*** Maven command failed:@\n*** %s@\n*** %s@\n"
(String.concat ~sep:" " (prog :: capture_args)) (String.concat ~sep:" " (prog :: capture_args))
(Unix.Exit_or_signal.to_string_hum status) (Unix.Exit_or_signal.to_string_hum status)

@ -63,8 +63,10 @@ module PVariant = struct
let ( = ) (v1: [> ]) (v2: [> ]) = Polymorphic_compare.( = ) v1 v2 let ( = ) (v1: [> ]) (v2: [> ]) = Polymorphic_compare.( = ) v1 v2
end end
let failwithf fmt = let failwith _ : [`use_Logging_die_instead] = assert false
Format.kfprintf (fun _ -> failwith (Format.flush_str_formatter ())) Format.str_formatter fmt
let invalid_argf fmt = let failwithf _ : [`use_Logging_die_instead] = assert false
Format.kfprintf (fun _ -> invalid_arg (Format.flush_str_formatter ())) Format.str_formatter fmt
let invalid_arg _ : [`use_Logging_die_instead] = assert false
let invalid_argf _ : [`use_Logging_die_instead] = assert false

@ -37,14 +37,14 @@ let load_models_tenv zip_channel =
Zip.copy_entry_to_file zip_channel entry temp_tenv_file ; Zip.copy_entry_to_file zip_channel entry temp_tenv_file ;
match Tenv.load_from_file temp_tenv_filename with match Tenv.load_from_file temp_tenv_filename with
| None | None
-> failwith "Models tenv file could not be loaded" -> L.(die InternalError) "Models tenv file could not be loaded"
| Some tenv | Some tenv
-> tenv -> tenv
with with
| Not_found | Not_found
-> failwith "Models tenv not found in jar file" -> L.(die InternalError) "Models tenv not found in jar file"
| Sys_error msg | Sys_error msg
-> failwith ("Models jar could not be opened " ^ msg) -> L.(die InternalError) "Models jar could not be opened: %s" msg
in in
DB.file_remove temp_tenv_filename ; models_tenv DB.file_remove temp_tenv_filename ; models_tenv
@ -65,7 +65,7 @@ let collect_specs_filenames jar_filename =
let add_models jar_filename = let add_models jar_filename =
models_jar := jar_filename ; models_jar := jar_filename ;
if Sys.file_exists !models_jar = `Yes then collect_specs_filenames jar_filename if Sys.file_exists !models_jar = `Yes then collect_specs_filenames jar_filename
else failwith "Java model file not found" else L.(die InternalError) "Java model file not found"
let is_model procname = String.Set.mem !models_specs_filenames (Typ.Procname.to_filename procname) let is_model procname = String.Set.mem !models_specs_filenames (Typ.Procname.to_filename procname)

@ -99,7 +99,7 @@ let add_cmethod source_file program linereader icfg cm proc_name =
| Some node | Some node
-> node -> node
| None | None
-> failwithf "No exn node found for %s" (Typ.Procname.to_string proc_name) -> L.(die InternalError) "No exn node found for %s" (Typ.Procname.to_string proc_name)
in in
let instrs = JBir.code jbir_code in let instrs = JBir.code jbir_code in
let context = JContext.create_context icfg procdesc jbir_code cn source_file program in let context = JContext.create_context icfg procdesc jbir_code cn source_file program in

@ -71,7 +71,8 @@ let load_tenv () =
| None | None
-> Tenv.create () -> Tenv.create ()
| Some _ when Config.models_mode | Some _ when Config.models_mode
-> failwithf "Unexpected tenv file %s found while generating the models" -> L.(die InternalError)
"Unexpected tenv file %s found while generating the models"
(DB.filename_to_string DB.global_tenv_fname) (DB.filename_to_string DB.global_tenv_fname)
| Some tenv | Some tenv
-> tenv -> tenv
@ -128,9 +129,9 @@ let main load_sources_and_classes =
| true, false | true, false
-> () -> ()
| false, false | false, false
-> failwith "Java model file is required" -> L.(die UserError) "Java model file is required"
| true, true | true, true
-> failwith "Not expecting model file when analyzing the models" -> L.(die UserError) "Not expecting model file when analyzing the models"
| false, true | false, true
-> JClasspath.add_models Config.models_jar ) ; -> JClasspath.add_models Config.models_jar ) ;
JBasics.set_permissive true ; JBasics.set_permissive true ;
@ -141,7 +142,7 @@ let main load_sources_and_classes =
| `FromArguments path | `FromArguments path
-> JClasspath.load_from_arguments path -> JClasspath.load_from_arguments path
in in
if String.Map.is_empty sources then failwith "Failed to load any Java source code" if String.Map.is_empty sources then L.(die UserError) "Failed to load any Java source code"
else do_all_files classpath sources classes else do_all_files classpath sources classes
let from_arguments path = main (`FromArguments path) let from_arguments path = main (`FromArguments path)

@ -232,7 +232,8 @@ let get_implementation cm =
| Javalib.Native | Javalib.Native
-> let cms = cm.Javalib.cm_class_method_signature in -> let cms = cm.Javalib.cm_class_method_signature in
let cn, ms = JBasics.cms_split cms in let cn, ms = JBasics.cms_split cms in
failwithf "native method %s found in %s@." (JBasics.ms_name ms) (JBasics.cn_name cn) L.(die InternalError)
"native method %s found in %s@." (JBasics.ms_name ms) (JBasics.cn_name cn)
| Javalib.Java t | Javalib.Java t
-> (* Sawja doesn't handle invokedynamic, and it will crash with a Match_failure if we give it -> (* Sawja doesn't handle invokedynamic, and it will crash with a Match_failure if we give it
bytecode with this instruction. hack around this problem by converting all invokedynamic's bytecode with this instruction. hack around this problem by converting all invokedynamic's

@ -86,7 +86,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
astate astate
| Call (_, Indirect _, _, _, _) | Call (_, Indirect _, _, _, _)
-> (* This should never happen in Java. Fail if it does. *) -> (* This should never happen in Java. Fail if it does. *)
failwithf "Unexpected indirect call %a" HilInstr.pp instr L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr
end end
(* Create an intraprocedural abstract interpreter from the transfer functions we defined *) (* Create an intraprocedural abstract interpreter from the transfer functions we defined *)
@ -123,5 +123,6 @@ let checker {Callbacks.summary; proc_desc; tenv} : Specs.summary =
report post proc_data ; report post proc_data ;
Summary.update_summary (convert_to_summary post) summary Summary.update_summary (convert_to_summary post) summary
| None | None
-> failwithf "Analyzer failed to compute post for %a" Typ.Procname.pp -> L.(die InternalError)
"Analyzer failed to compute post for %a" Typ.Procname.pp
(Procdesc.get_proc_name proc_data.pdesc) (Procdesc.get_proc_name proc_data.pdesc)

@ -76,7 +76,7 @@ module SourceKind = struct
| Typ.Procname.Block _ | Typ.Procname.Block _
-> None -> None
| pname | pname
-> failwithf "Non-C++ procname %a in C++ analysis@." Typ.Procname.pp pname -> L.(die InternalError) "Non-C++ procname %a in C++ analysis" Typ.Procname.pp pname
let get_tainted_formals pdesc _ = let get_tainted_formals pdesc _ =
let get_tainted_formals_ qualified_pname = let get_tainted_formals_ qualified_pname =
@ -211,7 +211,7 @@ module SinkKind = struct
| Typ.Procname.Block _ | Typ.Procname.Block _
-> None -> None
| pname | pname
-> failwithf "Non-C++ procname %a in C++ analysis@." Typ.Procname.pp pname -> L.(die InternalError) "Non-C++ procname %a in C++ analysis" Typ.Procname.pp pname
let pp fmt kind = let pp fmt kind =
F.fprintf fmt F.fprintf fmt

@ -73,7 +73,7 @@ include TaintAnalysis.Make (struct
| pname when BuiltinDecl.is_declared pname | pname when BuiltinDecl.is_declared pname
-> [] -> []
| pname | pname
-> failwithf "Non-Java procname %a in Java analysis@." Typ.Procname.pp pname -> L.(die InternalError) "Non-Java procname %a in Java analysis" Typ.Procname.pp pname
let get_model _ _ _ _ _ = None let get_model _ _ _ _ _ = None

@ -84,7 +84,7 @@ module SourceKind = struct
| pname when BuiltinDecl.is_declared pname | pname when BuiltinDecl.is_declared pname
-> None -> None
| pname | pname
-> failwithf "Non-Java procname %a in Java analysis@." Typ.Procname.pp pname -> L.(die InternalError) "Non-Java procname %a in Java analysis" Typ.Procname.pp pname
let get_tainted_formals pdesc tenv = let get_tainted_formals pdesc tenv =
let make_untainted (name, typ) = (name, typ, None) in let make_untainted (name, typ) = (name, typ, None) in
@ -148,8 +148,8 @@ module SourceKind = struct
| None | None
-> Source.all_formals_untainted pdesc ) -> Source.all_formals_untainted pdesc )
| procname | procname
-> failwithf "Non-Java procedure %a where only Java procedures are expected" Typ.Procname.pp -> L.(die InternalError)
procname "Non-Java procedure %a where only Java procedures are expected" Typ.Procname.pp procname
let pp fmt kind = let pp fmt kind =
F.fprintf fmt F.fprintf fmt
@ -284,7 +284,7 @@ module SinkKind = struct
| pname when BuiltinDecl.is_declared pname | pname when BuiltinDecl.is_declared pname
-> None -> None
| pname | pname
-> failwithf "Non-Java procname %a in Java analysis@." Typ.Procname.pp pname -> L.(die InternalError) "Non-Java procname %a in Java analysis" Typ.Procname.pp pname
let pp fmt kind = let pp fmt kind =
F.fprintf fmt F.fprintf fmt

@ -88,8 +88,8 @@ module Make (TaintSpecification : TaintSpec.S) = struct
TaintDomain.add_trace actual_ap (TraceDomain.add_source source trace) access_tree TaintDomain.add_trace actual_ap (TraceDomain.add_source source trace) access_tree
| _ | _
-> access_tree -> access_tree
| exception Failure _ | exception Failure s
-> failwithf "Bad source specification: index %d out of bounds" index -> L.(die InternalError) "Bad source specification: index %d out of bounds (%s)" index s
let endpoints = let endpoints =
(lazy (String.Set.of_list (QuandaryConfig.Endpoint.of_json Config.quandary_endpoints))) (lazy (String.Set.of_list (QuandaryConfig.Endpoint.of_json Config.quandary_endpoints)))
@ -266,8 +266,8 @@ module Make (TaintSpecification : TaintSpec.S) = struct
| None | None
-> access_tree_acc ) -> access_tree_acc )
| None | None
-> failwithf -> L.(die InternalError)
"Taint is supposed to flow into sink %a at index %d, but the index is out of bounds@\n" "Taint is supposed to flow into sink %a at index %d, but the index is out of bounds"
CallSite.pp callee_site sink_index CallSite.pp callee_site sink_index
| _ | _
-> access_tree_acc -> access_tree_acc
@ -493,8 +493,9 @@ module Make (TaintSpecification : TaintSpec.S) = struct
exec_write lhs_access_path rhs_exp access_tree exec_write lhs_access_path rhs_exp access_tree
|> exec_write dummy_ret_access_path rhs_exp |> exec_write dummy_ret_access_path rhs_exp
| _ | _
-> failwithf "Unexpected call to operator= %a in %a" HilInstr.pp instr -> L.(die InternalError)
Typ.Procname.pp callee_pname ) "Unexpected call to operator= %a in %a" HilInstr.pp instr Typ.Procname.pp
callee_pname )
| _ | _
-> let model = -> let model =
TaintSpecification.handle_unknown_call callee_pname (Option.map ~f:snd ret_opt) TaintSpecification.handle_unknown_call callee_pname (Option.map ~f:snd ret_opt)
@ -711,6 +712,6 @@ module Make (TaintSpecification : TaintSpec.S) = struct
-> Summary.update_summary (make_summary proc_data access_tree) summary -> Summary.update_summary (make_summary proc_data access_tree) summary
| None | None
-> if Procdesc.Node.get_succs (Procdesc.get_start_node proc_desc) <> [] then -> if Procdesc.Node.get_succs (Procdesc.get_start_node proc_desc) <> [] then
failwith "Couldn't compute post" L.(die InternalError) "Couldn't compute post"
else summary else summary
end end

@ -26,7 +26,7 @@ let test_file_renamings_from_json =
~cmp:DifferentialFilters.FileRenamings.VISIBLE_FOR_TESTING_DO_NOT_USE_DIRECTLY.equal exp ~cmp:DifferentialFilters.FileRenamings.VISIBLE_FOR_TESTING_DO_NOT_USE_DIRECTLY.equal exp
(test_output test_input) (test_output test_input)
| Raise exc | Raise exc
-> assert_raises exc (fun () -> test_output test_input) -> UnitUtils.assert_raises exc (fun () -> test_output test_input)
in in
[ ( "test_file_renamings_from_json_with_good_input" [ ( "test_file_renamings_from_json_with_good_input"
, "[" ^ "{\"current\": \"aaa.java\", \"previous\": \"BBB.java\"}," , "[" ^ "{\"current\": \"aaa.java\", \"previous\": \"BBB.java\"},"
@ -44,15 +44,16 @@ let test_file_renamings_from_json =
[]) ) []) )
; ( "test_file_renamings_from_json_with_well_formed_but_unexpected_input" ; ( "test_file_renamings_from_json_with_well_formed_but_unexpected_input"
, "{}" , "{}"
, Raise (Failure "Expected JSON list but got '{}'") ) , Raise (Logging.InferUserError ("Expected JSON list but got '{}'", "")) )
; ( "test_file_renamings_from_json_with_well_formed_but_unexpected_value" ; ( "test_file_renamings_from_json_with_well_formed_but_unexpected_value"
, "[{\"current\": 1, \"previous\": \"BBB.java\"}]" , "[{\"current\": 1, \"previous\": \"BBB.java\"}]"
, Raise , Raise
(Failure (Logging.InferUserError
( "Error parsing file renamings: \"current\" field is not a string" ( "Error parsing file renamings: \"current\" field is not a string"
^ "\nExpected JSON object of the following form: " ^ "\nExpected JSON object of the following form: "
^ "'{\"current\": \"aaa.java\", \"previous\": \"BBB.java\"}', " ^ "'{\"current\": \"aaa.java\", \"previous\": \"BBB.java\"}', "
^ "but instead got: '{\"current\":1,\"previous\":\"BBB.java\"}'" )) ) ^ "but instead got: '{\"current\":1,\"previous\":\"BBB.java\"}'"
, "" )) )
; ( "test_file_renamings_from_json_with_malformed_input" ; ( "test_file_renamings_from_json_with_malformed_input"
, "A" , "A"
, Raise (Yojson.Json_error "Line 1, bytes 0-1:\nInvalid token 'A'") ) ] , Raise (Yojson.Json_error "Line 1, bytes 0-1:\nInvalid token 'A'") ) ]

@ -0,0 +1,23 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
let erase_backtrace exn =
match exn with
| Logging.InferUserError (msg, _)
-> Logging.InferUserError (msg, "")
| Logging.InferExternalError (msg, _)
-> Logging.InferExternalError (msg, "")
| Logging.InferInternalError (msg, _)
-> Logging.InferInternalError (msg, "")
| _
-> exn
let assert_raises ?msg exn f =
OUnit2.assert_raises ?msg (erase_backtrace exn) (fun () ->
try f ()
with exn -> raise (erase_backtrace exn) )

@ -0,0 +1,14 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
val assert_raises : ?msg:string -> exn -> (unit -> 'a) -> unit
(** OUnit2.assert_raises checks that a function raises some exception that's exactly the same as a
reference exception, but some of our internal exceptions contain verbose and flaky data, eg
backtraces. This will normalize such known exceptions by erasing their verbose data. Use this if
you're suffering from OUnit2.assert_raises. *)

@ -14,7 +14,8 @@ let tests =
let open OUnit2 in let open OUnit2 in
let empty_string_test = let empty_string_test =
let empty_string_test_ _ = let empty_string_test_ _ =
assert_raises (Failure "Empty stack trace") (fun () -> Stacktrace.of_string "") UnitUtils.assert_raises (Logging.InferUserError ("Empty stack trace", "")) (fun () ->
Stacktrace.of_string "" )
in in
"empty_string" >:: empty_string_test_ "empty_string" >:: empty_string_test_
in in

Loading…
Cancel
Save