[reporting] add logging of call stats to backend

Summary:
- During the symbolic execution stage of the backend, Infer will log detailed stats about procedure calls
- Logging is accomplished directly within symExec/Tabulation
- call_result type is moved to tabulation.ml

CallStats was a broken module that allocated a lot of useless memory. Now, Specs.CallStats and InferPrint.CallsCsv as well as the Calls report kind in InferPrint no longer exist.

Reviewed By: dulmarod

Differential Revision: D7016439

fbshipit-source-id: 40911ee
master
Varun Arora 7 years ago committed by Facebook Github Bot
parent 49e05217fe
commit e90eaeab49

@ -380,24 +380,6 @@ let pp_text_of_report fmt report =
List.iter ~f:pp_row report ; F.fprintf fmt "@?" List.iter ~f:pp_row report ; F.fprintf fmt "@?"
module CallsCsv = struct
(** Write proc summary stats in csv format *)
let pp_calls fmt summary =
let pp x = F.fprintf fmt x in
let stats = summary.Specs.stats in
let caller_name = Specs.get_proc_name summary in
let do_call (callee_name, loc) trace =
pp "\"%s\"," (Escape.escape_csv (Typ.Procname.to_string caller_name)) ;
pp "\"%s\"," (Escape.escape_csv (Typ.Procname.to_filename caller_name)) ;
pp "\"%s\"," (Escape.escape_csv (Typ.Procname.to_string callee_name)) ;
pp "\"%s\"," (Escape.escape_csv (Typ.Procname.to_filename callee_name)) ;
pp "%s," (SourceFile.to_string (Specs.get_loc summary).Location.file) ;
pp "%d," loc.Location.line ;
pp "%a@\n" Specs.CallStats.pp_trace trace
in
Specs.CallStats.iter do_call stats.Specs.call_stats
end
module Stats = struct module Stats = struct
type t = type t =
{ files: (SourceFile.t, unit) Hashtbl.t { files: (SourceFile.t, unit) Hashtbl.t
@ -643,7 +625,7 @@ let error_filter filters proc_name file error_desc error_name =
&& filters.Inferconfig.error_filter error_name && filters.Inferconfig.proc_filter proc_name && filters.Inferconfig.error_filter error_name && filters.Inferconfig.proc_filter proc_name
type report_kind = Issues | Procs | Stats | Calls | Summary [@@deriving compare] type report_kind = Issues | Procs | Stats | Summary [@@deriving compare]
let _string_of_report_kind = function let _string_of_report_kind = function
| Issues -> | Issues ->
@ -652,8 +634,6 @@ let _string_of_report_kind = function
"Procs" "Procs"
| Stats -> | Stats ->
"Stats" "Stats"
| Calls ->
"Calls"
| Summary -> | Summary ->
"Summary" "Summary"
@ -723,15 +703,6 @@ let pp_procs_in_format (format_kind, (outfile_opt: Utils.outfile option)) =
L.(die InternalError) "Printing procs in json/tests/text/logs is not implemented" L.(die InternalError) "Printing procs in json/tests/text/logs is not implemented"
let pp_calls_in_format (format_kind, (outfile_opt: Utils.outfile option)) =
match format_kind with
| Csv ->
let outf = get_outfile outfile_opt in
CallsCsv.pp_calls outf.fmt
| Json | Tests | Text | Logs ->
L.(die InternalError) "Printing calls in json/tests/text 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 ->
@ -766,14 +737,6 @@ let pp_procs summary procs_format_list =
List.iter ~f:pp_procs_in_format procs_format_list List.iter ~f:pp_procs_in_format procs_format_list
let pp_calls summary calls_format_list =
let pp_calls_in_format format =
let pp_calls = pp_calls_in_format format in
pp_calls summary
in
List.iter ~f:pp_calls_in_format calls_format_list
let pp_stats error_filter linereader summary stats stats_format_list = let pp_stats error_filter linereader summary stats stats_format_list =
let pp_stats_in_format format = let pp_stats_in_format format =
let pp_stats = pp_stats_in_format format in let pp_stats = pp_stats_in_format format in
@ -795,8 +758,6 @@ let pp_summary_by_report_kind formats_by_report_kind summary error_filter linere
pp_procs summary format_list pp_procs summary format_list
| Stats, _ :: _ -> | Stats, _ :: _ ->
pp_stats (error_filter file) linereader summary stats format_list pp_stats (error_filter file) linereader summary stats format_list
| Calls, _ :: _ ->
pp_calls summary format_list
| Summary, _ when InferCommand.equal Config.command Report && not Config.quiet -> | Summary, _ when InferCommand.equal Config.command Report && not Config.quiet ->
pp_summary summary pp_summary summary
| _ -> | _ ->
@ -927,8 +888,6 @@ let init_issues_format_list report_json =
let init_procs_format_list () = Option.value_map ~f:(mk_format Csv) ~default:[] Config.procs_csv let init_procs_format_list () = Option.value_map ~f:(mk_format Csv) ~default:[] Config.procs_csv
let init_calls_format_list () = Option.value_map ~f:(mk_format Csv) ~default:[] Config.calls_csv
let init_stats_format_list () = let init_stats_format_list () =
let csv_format = Option.value_map ~f:(mk_format Csv) ~default:[] Config.stats_report in let csv_format = Option.value_map ~f:(mk_format Csv) ~default:[] Config.stats_report in
let logs_format = if Config.log_events then [(Logs, None)] else [] in let logs_format = if Config.log_events then [(Logs, None)] else [] in
@ -941,7 +900,7 @@ let init_files format_list_by_kind =
match (format_kind, report_kind) with match (format_kind, report_kind) with
| Csv, Issues -> | Csv, Issues ->
L.(die InternalError) "Printing issues in a CSV format is not implemented" L.(die InternalError) "Printing issues in a CSV format is not implemented"
| Logs, (Issues | Procs | Calls | Summary) -> | Logs, (Issues | Procs | Summary) ->
L.(die InternalError) "Logging these reports is not implemented" L.(die InternalError) "Logging these reports is not implemented"
| Csv, Procs -> | Csv, Procs ->
let outfile = get_outfile outfile_opt in let outfile = get_outfile outfile_opt in
@ -952,11 +911,7 @@ let init_files format_list_by_kind =
| Json, Issues -> | Json, Issues ->
let outfile = get_outfile outfile_opt in let outfile = get_outfile outfile_opt in
IssuesJson.pp_json_open outfile.fmt () IssuesJson.pp_json_open outfile.fmt ()
| Csv, (Calls | Summary) | Csv, Summary | Logs, Stats | Json, (Procs | Stats | Summary) | Tests, _ | Text, _ ->
| Logs, Stats
| Json, (Procs | Stats | Calls | Summary)
| Tests, _
| Text, _ ->
() ()
in in
List.iter ~f:init_files_of_format format_list List.iter ~f:init_files_of_format format_list
@ -968,7 +923,7 @@ let finalize_and_close_files format_list_by_kind (stats: Stats.t) =
let close_files_of_report_kind (report_kind, format_list) = let close_files_of_report_kind (report_kind, format_list) =
let close_files_of_format (format_kind, (outfile_opt: Utils.outfile option)) = let close_files_of_format (format_kind, (outfile_opt: Utils.outfile option)) =
( match (format_kind, report_kind) with ( match (format_kind, report_kind) with
| Logs, (Issues | Procs | Calls | Summary) -> | Logs, (Issues | Procs | Summary) ->
L.(die InternalError) "Logging these reports is not implemented" L.(die InternalError) "Logging these reports is not implemented"
| Csv, Stats -> | Csv, Stats ->
let outfile = get_outfile outfile_opt in let outfile = get_outfile outfile_opt in
@ -976,9 +931,9 @@ let finalize_and_close_files format_list_by_kind (stats: Stats.t) =
| Json, Issues -> | Json, Issues ->
let outfile = get_outfile outfile_opt in let outfile = get_outfile outfile_opt in
IssuesJson.pp_json_close outfile.fmt () IssuesJson.pp_json_close outfile.fmt ()
| Csv, (Issues | Procs | Calls | Summary) | Csv, (Issues | Procs | Summary)
| Logs, Stats | Logs, Stats
| Json, (Procs | Stats | Calls | Summary) | Json, (Procs | Stats | Summary)
| Tests, _ | Tests, _
| Text, _ -> | Text, _ ->
() ) ; () ) ;
@ -1019,7 +974,6 @@ let main ~report_json =
let formats_by_report_kind = let formats_by_report_kind =
[ (Issues, issue_formats) [ (Issues, issue_formats)
; (Procs, init_procs_format_list ()) ; (Procs, init_procs_format_list ())
; (Calls, init_calls_format_list ())
; (Stats, init_stats_format_list ()) ; (Stats, init_stats_format_list ())
; (Summary, []) ] ; (Summary, []) ]
in in

@ -237,92 +237,13 @@ let spec_normalize = NormSpec.normalize
(** Cast a list of normalized specs to a list of specs *) (** Cast a list of normalized specs to a list of specs *)
let normalized_specs_to_specs = NormSpec.tospecs let normalized_specs_to_specs = NormSpec.tospecs
module CallStats = struct
(** module for tracing stats of function calls *)
module PnameLocHash = Hashtbl.Make (struct
type t = Typ.Procname.t * Location.t
let hash (pname, loc) = Hashtbl.hash (Typ.Procname.hash_pname pname, loc.Location.line)
let equal = [%compare.equal : Typ.Procname.t * Location.t]
end)
(** kind of result of a procedure call *)
type call_result =
| CR_success (** successful call *)
| CR_not_met (** precondition not met *)
| CR_not_found (** the callee has no specs *)
| CR_skip (** the callee was skipped *)
type trace = (call_result * bool) list
type t = trace PnameLocHash.t
let trace_add tr (res: call_result) in_footprint = (res, in_footprint) :: tr
let empty_trace : trace = []
let init calls =
let hash = PnameLocHash.create 1 in
let do_call pn_loc = PnameLocHash.add hash pn_loc empty_trace in
List.iter ~f:do_call calls ; hash
let trace t proc_name loc res in_footprint =
let tr_old =
try PnameLocHash.find t (proc_name, loc) with Not_found ->
PnameLocHash.add t (proc_name, loc) empty_trace ;
empty_trace
in
let tr_new = trace_add tr_old res in_footprint in
PnameLocHash.replace t (proc_name, loc) tr_new
let tr_elem_str (cr, in_footprint) =
let s1 =
match cr with
| CR_success ->
"OK"
| CR_not_met ->
"NotMet"
| CR_not_found ->
"NotFound"
| CR_skip ->
"Skip"
in
let s2 = if in_footprint then "FP" else "RE" in
s1 ^ ":" ^ s2
let pp_trace fmt tr = Pp.seq (fun fmt x -> F.fprintf fmt "%s" (tr_elem_str x)) fmt (List.rev tr)
let iter f t =
let elems = ref [] in
PnameLocHash.iter (fun x tr -> elems := (x, tr) :: !elems) t ;
let sorted_elems =
let compare (pname_loc1, _) (pname_loc2, _) =
[%compare : Typ.Procname.t * Location.t] pname_loc1 pname_loc2
in
List.sort ~cmp:compare !elems
in
List.iter ~f:(fun (x, tr) -> f x tr) sorted_elems
(*
let pp fmt t =
let do_call (pname, loc) tr =
F.fprintf fmt "%a %a: %a@\n" Typ.Procname.pp pname Location.pp loc pp_trace tr in
iter do_call t
*)
end
(** Execution statistics *) (** Execution statistics *)
type stats = type stats =
{ stats_failure: SymOp.failure_kind option { stats_failure: SymOp.failure_kind option
(** what type of failure stopped the analysis (if any) *) (** what type of failure stopped the analysis (if any) *)
; symops: int (** Number of SymOp's throughout the whole analysis of the function *) ; symops: int (** Number of SymOp's throughout the whole analysis of the function *)
; mutable nodes_visited_fp: IntSet.t (** Nodes visited during the footprint phase *) ; mutable nodes_visited_fp: IntSet.t (** Nodes visited during the footprint phase *)
; mutable nodes_visited_re: IntSet.t (** Nodes visited during the re-execution phase *) ; mutable nodes_visited_re: IntSet.t (** Nodes visited during the re-execution phase *) }
; call_stats: CallStats.t }
type status = Pending | Analyzed [@@deriving compare] type status = Pending | Analyzed [@@deriving compare]
@ -537,11 +458,7 @@ let pp_summary_html source color fmt summary =
let empty_stats = let empty_stats =
{ stats_failure= None {stats_failure= None; symops= 0; nodes_visited_fp= IntSet.empty; nodes_visited_re= IntSet.empty}
; symops= 0
; nodes_visited_fp= IntSet.empty
; nodes_visited_re= IntSet.empty
; call_stats= CallStats.init [] (* TODO(T23648322): remove the call_stats *) }
let payload_compact sh payload = let payload_compact sh payload =

@ -72,38 +72,13 @@ module NormSpec : sig
(** Erase join info from pre of spec *) (** Erase join info from pre of spec *)
end end
(** module for tracing stats of function calls *)
module CallStats : sig
type t
(** kind of result of a procedure call *)
type call_result =
| CR_success (** successful call *)
| CR_not_met (** precondition not met *)
| CR_not_found (** the callee has no specs *)
| CR_skip (** the callee was skipped *)
(** trace of an occurrence of function call *)
type trace = (call_result * bool) list
val iter : (Typ.Procname.t * Location.t -> trace -> unit) -> t -> unit
(** iterate over results of procedure calls *)
val trace : t -> Typ.Procname.t -> Location.t -> call_result -> bool -> unit
(** trace a procedure call *)
val pp_trace : Format.formatter -> trace -> unit
(** pretty print a call trace *)
end
(** Execution statistics *) (** Execution statistics *)
type stats = type stats =
{ stats_failure: SymOp.failure_kind option { stats_failure: SymOp.failure_kind option
(** what type of failure stopped the analysis (if any) *) (** what type of failure stopped the analysis (if any) *)
; symops: int (** Number of SymOp's throughout the whole analysis of the function *) ; symops: int (** Number of SymOp's throughout the whole analysis of the function *)
; mutable nodes_visited_fp: IntSet.t (** Nodes visited during the footprint phase *) ; mutable nodes_visited_fp: IntSet.t (** Nodes visited during the footprint phase *)
; mutable nodes_visited_re: IntSet.t (** Nodes visited during the re-execution phase *) ; mutable nodes_visited_re: IntSet.t (** Nodes visited during the re-execution phase *) }
; call_stats: CallStats.t }
(** Analysis status of the procedure: (** Analysis status of the procedure:
- Pending means that the summary has been created by the procedure has not been analyzed yet - Pending means that the summary has been created by the procedure has not been analyzed yet

@ -1078,8 +1078,8 @@ let rec sym_exec tenv current_pdesc instr_ (prop_: Prop.normal Prop.t) path
| None -> | None ->
() ()
| Some summary -> | Some summary ->
Specs.CallStats.trace summary.Specs.stats.Specs.call_stats callee_pname loc let proc_name = Specs.get_proc_name summary in
Specs.CallStats.CR_skip !Config.footprint ) ; Tabulation.log_call_trace proc_name callee_pname loc Tabulation.CR_skip ) ;
unknown_or_scan_call ~is_scan:false ~reason ret_typ_opt ret_annots unknown_or_scan_call ~is_scan:false ~reason ret_typ_opt ret_annots
Builtin. Builtin.
{ pdesc= current_pdesc { pdesc= current_pdesc

@ -25,6 +25,24 @@ type splitting =
; frame_typ: (Exp.t * Exp.t) list ; frame_typ: (Exp.t * Exp.t) list
; missing_typ: (Exp.t * Exp.t) list } ; missing_typ: (Exp.t * Exp.t) list }
(** kind of result of a procedure call *)
type call_result =
| CR_success (** successful call *)
| CR_not_met (** precondition not met *)
| CR_not_found (** the callee has no specs *)
| CR_skip (** the callee was skipped *)
let string_of_call_result = function
| CR_success ->
"OK"
| CR_not_met ->
"NotMet"
| CR_not_found ->
"NotFound"
| CR_skip ->
"Skip"
type deref_error = type deref_error =
| Deref_freed of PredSymb.res_action (** dereference a freed pointer *) | Deref_freed of PredSymb.res_action (** dereference a freed pointer *)
| Deref_minusone (** dereference -1 *) | Deref_minusone (** dereference -1 *)
@ -65,6 +83,18 @@ let print_results tenv actual_pre results =
L.d_strln "***** END RESULTS FUNCTION CALL *******" L.d_strln "***** END RESULTS FUNCTION CALL *******"
let log_call_trace caller_name callee_name loc res =
let call_trace =
EventLogger.CallTrace
{ call_location= loc
; call_result= string_of_call_result res
; callee_name= Typ.Procname.to_string callee_name
; caller_name= Typ.Procname.to_string caller_name
; lang= Typ.Procname.get_language caller_name |> Language.to_explicit_string }
in
if !Config.footprint then EventLogger.log call_trace else ()
(***************) (***************)
(** Rename the variables in the spec. *) (** Rename the variables in the spec. *)
@ -102,7 +132,7 @@ let spec_find_rename trace_call summary : (int * Prop.exposed Specs.spec) list *
let specs = Specs.get_specs_from_payload summary in let specs = Specs.get_specs_from_payload summary in
let formals = Specs.get_formals summary in let formals = Specs.get_formals summary in
if List.is_empty specs then ( if List.is_empty specs then (
trace_call Specs.CallStats.CR_not_found ; trace_call CR_not_found ;
raise raise
(Exceptions.Precondition_not_found (Exceptions.Precondition_not_found
(Localise.verbatim_desc (Typ.Procname.to_string proc_name), __POS__)) ) ; (Localise.verbatim_desc (Typ.Procname.to_string proc_name), __POS__)) ) ;
@ -1223,17 +1253,17 @@ let exe_call_postprocess tenv ret_id trace_call callee_pname callee_attrs loc re
in in
match error with match error with
| Dereference_error (Deref_minusone, desc, path_opt) -> | Dereference_error (Deref_minusone, desc, path_opt) ->
trace_call Specs.CallStats.CR_not_met ; trace_call CR_not_met ;
extend_path path_opt None ; extend_path path_opt None ;
raise raise
(Exceptions.Dangling_pointer_dereference (Some PredSymb.DAminusone, desc, __POS__)) (Exceptions.Dangling_pointer_dereference (Some PredSymb.DAminusone, desc, __POS__))
| Dereference_error (Deref_undef_exp, desc, path_opt) -> | Dereference_error (Deref_undef_exp, desc, path_opt) ->
trace_call Specs.CallStats.CR_not_met ; trace_call CR_not_met ;
extend_path path_opt None ; extend_path path_opt None ;
raise raise
(Exceptions.Dangling_pointer_dereference (Some PredSymb.DAuninit, desc, __POS__)) (Exceptions.Dangling_pointer_dereference (Some PredSymb.DAuninit, desc, __POS__))
| Dereference_error (Deref_null pos, desc, path_opt) -> | Dereference_error (Deref_null pos, desc, path_opt) ->
trace_call Specs.CallStats.CR_not_met ; trace_call CR_not_met ;
extend_path path_opt (Some pos) ; extend_path path_opt (Some pos) ;
if Localise.is_parameter_not_null_checked_desc desc then if Localise.is_parameter_not_null_checked_desc desc then
raise (Exceptions.Parameter_not_null_checked (desc, __POS__)) raise (Exceptions.Parameter_not_null_checked (desc, __POS__))
@ -1245,15 +1275,15 @@ let exe_call_postprocess tenv ret_id trace_call callee_pname callee_attrs loc re
raise (Exceptions.Empty_vector_access (desc, __POS__)) raise (Exceptions.Empty_vector_access (desc, __POS__))
else raise (Exceptions.Null_dereference (desc, __POS__)) else raise (Exceptions.Null_dereference (desc, __POS__))
| Dereference_error (Deref_freed _, desc, path_opt) -> | Dereference_error (Deref_freed _, desc, path_opt) ->
trace_call Specs.CallStats.CR_not_met ; trace_call CR_not_met ;
extend_path path_opt None ; extend_path path_opt None ;
raise (Exceptions.Use_after_free (desc, __POS__)) raise (Exceptions.Use_after_free (desc, __POS__))
| Dereference_error (Deref_undef (_, _, pos), desc, path_opt) -> | Dereference_error (Deref_undef (_, _, pos), desc, path_opt) ->
trace_call Specs.CallStats.CR_not_met ; trace_call CR_not_met ;
extend_path path_opt (Some pos) ; extend_path path_opt (Some pos) ;
raise (Exceptions.Skip_pointer_dereference (desc, __POS__)) raise (Exceptions.Skip_pointer_dereference (desc, __POS__))
| Prover_checks _ | Cannot_combine | Missing_sigma_not_empty | Missing_fld_not_empty -> | Prover_checks _ | Cannot_combine | Missing_sigma_not_empty | Missing_fld_not_empty ->
trace_call Specs.CallStats.CR_not_met ; trace_call CR_not_met ;
assert false ) assert false )
| [] -> | [] ->
(* no dereference error detected *) (* no dereference error detected *)
@ -1263,7 +1293,7 @@ let exe_call_postprocess tenv ret_id trace_call callee_pname callee_attrs loc re
else if List.exists else if List.exists
~f:(function ~f:(function
| Prover_checks (check :: _) -> | Prover_checks (check :: _) ->
trace_call Specs.CallStats.CR_not_met ; trace_call CR_not_met ;
let exn = get_check_exn tenv check callee_pname loc __POS__ in let exn = get_check_exn tenv check callee_pname loc __POS__ in
raise exn raise exn
| _ -> | _ ->
@ -1272,7 +1302,7 @@ let exe_call_postprocess tenv ret_id trace_call callee_pname callee_attrs loc re
then call_desc (Some Localise.Pnm_bounds) then call_desc (Some Localise.Pnm_bounds)
else call_desc None else call_desc None
in in
trace_call Specs.CallStats.CR_not_met ; trace_call CR_not_met ;
raise (Exceptions.Precondition_not_met (desc, __POS__)) raise (Exceptions.Precondition_not_met (desc, __POS__))
else else
(* combine the valid results, and store diverging states *) (* combine the valid results, and store diverging states *)
@ -1304,14 +1334,14 @@ let exe_call_postprocess tenv ret_id trace_call callee_pname callee_attrs loc re
(List.map ~f:(fun vr -> (vr.vr_pi, vr.vr_cons_res)) valid_res_miss_pi) (List.map ~f:(fun vr -> (vr.vr_pi, vr.vr_cons_res)) valid_res_miss_pi)
with with
| None -> | None ->
trace_call Specs.CallStats.CR_not_met ; trace_call CR_not_met ;
raise (Exceptions.Precondition_not_met (call_desc None, __POS__)) raise (Exceptions.Precondition_not_met (call_desc None, __POS__))
| Some cover -> | Some cover ->
L.d_strln "Found minimum cover" ; L.d_strln "Found minimum cover" ;
List.iter ~f:print_pi (List.map ~f:fst cover) ; List.iter ~f:print_pi (List.map ~f:fst cover) ;
List.concat_map ~f:snd cover ) List.concat_map ~f:snd cover )
in in
trace_call Specs.CallStats.CR_success ; trace_call CR_success ;
let res = let res =
List.map List.map
~f:(fun (p, path) -> (quantify_path_idents_remove_constant_strings tenv p, path)) ~f:(fun (p, path) -> (quantify_path_idents_remove_constant_strings tenv p, path))
@ -1347,16 +1377,13 @@ let exe_function_call callee_summary tenv ret_id_opt caller_pdesc callee_pname l
prop path = prop path =
let callee_attrs = Specs.get_attributes callee_summary in let callee_attrs = Specs.get_attributes callee_summary in
let caller_pname = Procdesc.get_proc_name caller_pdesc in let caller_pname = Procdesc.get_proc_name caller_pdesc in
let caller_summary = Specs.get_summary_unsafe "exe_function_call" caller_pname in let trace_call = log_call_trace caller_pname callee_pname loc in
let trace_call res =
Specs.CallStats.trace caller_summary.Specs.stats.Specs.call_stats callee_pname loc res
!Config.footprint
in
let spec_list, formal_params = spec_find_rename trace_call callee_summary in let spec_list, formal_params = spec_find_rename trace_call callee_summary in
let nspecs = List.length spec_list in let nspecs = List.length spec_list in
L.d_strln L.d_strln
("Found " ^ string_of_int nspecs ^ " specs for function " ^ Typ.Procname.to_string callee_pname) ; (F.sprintf "Found %d specs for function %s" nspecs (Typ.Procname.to_string callee_pname)) ;
L.d_strln ("START EXECUTING SPECS FOR " ^ Typ.Procname.to_string callee_pname ^ " from state") ; L.d_strln
(F.sprintf "START EXECUTING SPECS FOR %s from state" (Typ.Procname.to_string callee_pname)) ;
Prop.d_prop prop ; Prop.d_prop prop ;
L.d_ln () ; L.d_ln () ;
let exe_one_spec (n, spec) = let exe_one_spec (n, spec) =

@ -10,6 +10,15 @@
open! IStd open! IStd
(** kind of result of a procedure call *)
type call_result =
| CR_success (** successful call *)
| CR_not_met (** precondition not met *)
| CR_not_found (** the callee has no specs *)
| CR_skip (** the callee was skipped *)
val log_call_trace : Typ.Procname.t -> Typ.Procname.t -> Location.t -> call_result -> unit
(** Interprocedural footprint analysis *) (** Interprocedural footprint analysis *)
val remove_constant_string_class : Tenv.t -> 'a Prop.t -> Prop.normal Prop.t val remove_constant_string_class : Tenv.t -> 'a Prop.t -> Prop.normal Prop.t

@ -857,12 +857,6 @@ and buck_out =
~meta:"dir" "Specify the root directory of buck-out" ~meta:"dir" "Specify the root directory of buck-out"
and calls_csv =
CLOpt.mk_path_opt ~deprecated:["calls"] ~long:"calls-csv"
~in_help:InferCommand.([(Report, manual_generic)])
~meta:"file" "Write individual calls in CSV format to $(i,file)"
and capture = and capture =
CLOpt.mk_bool ~long:"capture" ~default:true CLOpt.mk_bool ~long:"capture" ~default:true
"capture and translate source files into infer's intermediate language for analysis" "capture and translate source files into infer's intermediate language for analysis"
@ -2265,8 +2259,6 @@ and buck_out = !buck_out
and bufferoverrun = !bufferoverrun and bufferoverrun = !bufferoverrun
and calls_csv = !calls_csv
and capture = and capture =
(* take `--clang-frontend-action` as the source of truth as long as that option exists *) (* take `--clang-frontend-action` as the source of truth as long as that option exists *)
match !clang_frontend_action with match !clang_frontend_action with

@ -273,8 +273,6 @@ val buck_out : string option
val bufferoverrun : bool val bufferoverrun : bool
val calls_csv : string option
val capture : bool val capture : bool
val captured_dir : string val captured_dir : string

@ -105,6 +105,27 @@ let create_analysis_stats_row base record =
|> add_int ~key:"symops" ~data:record.symops |> add_int ~key:"symops" ~data:record.symops
type call_trace =
{ call_location: Location.t
; call_result: string
; callee_name: string
; caller_name: string
; lang: string }
let create_call_trace_row base record =
let open JsonBuilder in
base
|> add_string ~key:"call_location"
~data:
(String.concat
[string_of_int record.call_location.line; ":"; string_of_int record.call_location.col])
|> add_string ~key:"source_file" ~data:(SourceFile.to_rel_path record.call_location.file)
|> add_string ~key:"call_result" ~data:record.call_result
|> add_string ~key:"callee_name" ~data:record.callee_name
|> add_string ~key:"caller_name" ~data:record.caller_name
|> add_string ~key:"lang" ~data:record.lang
type frontend_exception = type frontend_exception =
{ ast_node: string option { ast_node: string option
; exception_file: string ; exception_file: string
@ -155,6 +176,7 @@ let create_procedures_translated_row base record =
type event = type event =
| AnalysisStats of analysis_stats | AnalysisStats of analysis_stats
| CallTrace of call_trace
| FrontendException of frontend_exception | FrontendException of frontend_exception
| ProceduresTranslatedSummary of procedures_translated | ProceduresTranslatedSummary of procedures_translated
| UncaughtException of exn * int | UncaughtException of exn * int
@ -163,6 +185,8 @@ let string_of_event event =
match event with match event with
| AnalysisStats _ -> | AnalysisStats _ ->
"AnalysisStats" "AnalysisStats"
| CallTrace _ ->
"CallTrace"
| FrontendException _ -> | FrontendException _ ->
"FrontendException" "FrontendException"
| ProceduresTranslatedSummary _ -> | ProceduresTranslatedSummary _ ->
@ -214,6 +238,8 @@ module LoggerImpl : S = struct
( match event with ( match event with
| AnalysisStats record -> | AnalysisStats record ->
create_analysis_stats_row base record create_analysis_stats_row base record
| CallTrace record ->
create_call_trace_row base record
| FrontendException record -> | FrontendException record ->
create_frontend_exception_row base record create_frontend_exception_row base record
| ProceduresTranslatedSummary record -> | ProceduresTranslatedSummary record ->

@ -18,6 +18,13 @@ type analysis_stats =
; num_preposts: int ; num_preposts: int
; symops: int } ; symops: int }
type call_trace =
{ call_location: Location.t
; call_result: string
; callee_name: string
; caller_name: string
; lang: string }
type frontend_exception = type frontend_exception =
{ ast_node: string option { ast_node: string option
; exception_file: string ; exception_file: string
@ -35,6 +42,7 @@ type procedures_translated =
type event = type event =
| AnalysisStats of analysis_stats | AnalysisStats of analysis_stats
| CallTrace of call_trace
| FrontendException of frontend_exception | FrontendException of frontend_exception
| ProceduresTranslatedSummary of procedures_translated | ProceduresTranslatedSummary of procedures_translated
| UncaughtException of exn * int (** exception, exitcode *) | UncaughtException of exn * int (** exception, exitcode *)

Loading…
Cancel
Save