From 11e3acb20e5f998efb82fcefb799fcce81613388 Mon Sep 17 00:00:00 2001 From: Sungkeun Cho Date: Tue, 2 Mar 2021 01:48:48 -0800 Subject: [PATCH] [ConfigImpact] Print config-impact-report.json Summary: The config impact checker prints ungated callees in a separate file config-impact-report.json, because its results should be compared before actual reporting as the cost checker does. Reviewed By: ezgicicek Differential Revision: D26665097 fbshipit-source-id: 0c6e13403 --- infer/src/atd/jsonbug.atd | 10 +++++ infer/src/backend/Summary.ml | 16 +++++-- infer/src/backend/Summary.mli | 9 +++- infer/src/base/ResultsDirEntryName.ml | 6 +++ infer/src/base/ResultsDirEntryName.mli | 1 + infer/src/checkers/ConfigImpactAnalysis.ml | 6 +++ infer/src/checkers/ConfigImpactAnalysis.mli | 8 ++++ infer/src/integration/Driver.ml | 4 +- infer/src/integration/JsonReports.ml | 47 ++++++++++++++++++--- infer/src/integration/JsonReports.mli | 2 +- infer/src/integration/dune.in | 4 +- 11 files changed, 97 insertions(+), 16 deletions(-) diff --git a/infer/src/atd/jsonbug.atd b/infer/src/atd/jsonbug.atd index 612ed2c9f..27507cac4 100644 --- a/infer/src/atd/jsonbug.atd +++ b/infer/src/atd/jsonbug.atd @@ -147,3 +147,13 @@ type cost_item = { } type costs_report = cost_item list + +type config_impact_item = { + hash : string; + loc : loc; + procedure_name : string; + procedure_id : string; + unchecked_callees : string; +} + +type config_impact_report = config_impact_item list diff --git a/infer/src/backend/Summary.ml b/infer/src/backend/Summary.ml index cbb5de54e..9405bdd6d 100644 --- a/infer/src/backend/Summary.ml +++ b/infer/src/backend/Summary.ml @@ -124,10 +124,18 @@ let pp_html source fmt summary = module ReportSummary = struct - type t = {loc: Location.t; cost_opt: CostDomain.summary option; err_log: Errlog.t} + type t = + { loc: Location.t + ; cost_opt: CostDomain.summary option + ; config_impact_opt: ConfigImpactAnalysis.Summary.t option + ; err_log: Errlog.t } let of_full_summary (f : full_summary) = - ({loc= get_loc f; cost_opt= f.payloads.Payloads.cost; err_log= f.err_log} : t) + ( { loc= get_loc f + ; cost_opt= f.payloads.Payloads.cost + ; config_impact_opt= f.payloads.Payloads.config_impact_analysis + ; err_log= f.err_log } + : t ) module SQLite = SqliteUtils.MarshalledDataNOTForComparison (struct @@ -333,10 +341,10 @@ module OnDisk = struct ~f:(fun stmt -> let proc_name = Sqlite3.column stmt 0 |> Procname.SQLite.deserialize in if filter dummy_source_file proc_name then - let ({loc; cost_opt; err_log} : ReportSummary.t) = + let ({loc; cost_opt; config_impact_opt; err_log} : ReportSummary.t) = Sqlite3.column stmt 1 |> ReportSummary.SQLite.deserialize in - f proc_name loc cost_opt err_log ) + f proc_name loc cost_opt config_impact_opt err_log ) let make_filtered_iterator_from_config ~iter ~f = diff --git a/infer/src/backend/Summary.mli b/infer/src/backend/Summary.mli index 7f9952dfc..15c49fde5 100644 --- a/infer/src/backend/Summary.mli +++ b/infer/src/backend/Summary.mli @@ -87,7 +87,14 @@ module OnDisk : sig (** Iterates over all stored summaries *) val iter_report_summaries_from_config : - f:(Procname.t -> Location.t -> CostDomain.summary option -> Errlog.t -> unit) -> unit + f: + ( Procname.t + -> Location.t + -> CostDomain.summary option + -> ConfigImpactAnalysis.Summary.t option + -> Errlog.t + -> unit) + -> unit (** Iterates over all analysis artefacts listed above, for each procedure *) val pp_specs_from_config : Format.formatter -> unit diff --git a/infer/src/base/ResultsDirEntryName.ml b/infer/src/base/ResultsDirEntryName.ml index fa0f94cd3..25a0120a2 100644 --- a/infer/src/base/ResultsDirEntryName.ml +++ b/infer/src/base/ResultsDirEntryName.ml @@ -26,6 +26,7 @@ type id = | PerfEvents | ProcnamesLocks | RacerDIssues + | ReportConfigImpactJson | ReportCostsJson | ReportHtml | ReportJson @@ -133,6 +134,11 @@ let of_id = function ; kind= IssuesDirectory ; before_incremental_analysis= Delete ; before_caching_capture= Delete } + | ReportConfigImpactJson -> + { rel_path= "config-impact-report.json" + ; kind= File + ; before_incremental_analysis= Delete + ; before_caching_capture= Delete } | ReportCostsJson -> { rel_path= "costs-report.json" ; kind= File diff --git a/infer/src/base/ResultsDirEntryName.mli b/infer/src/base/ResultsDirEntryName.mli index 18053a6b4..e065b415d 100644 --- a/infer/src/base/ResultsDirEntryName.mli +++ b/infer/src/base/ResultsDirEntryName.mli @@ -27,6 +27,7 @@ type id = | ProcnamesLocks (** directory of per-{!Procname.t} file locks, used by the analysis scheduler in certain modes *) | RacerDIssues (** directory of issues reported by the RacerD analysis *) + | ReportConfigImpactJson (** reports of the config impact analysis *) | ReportCostsJson (** reports of the costs analysis *) | ReportHtml (** directory of the HTML report *) | ReportJson (** the main product of the analysis: [report.json] *) diff --git a/infer/src/checkers/ConfigImpactAnalysis.ml b/infer/src/checkers/ConfigImpactAnalysis.ml index ef4c72a39..c066ff903 100644 --- a/infer/src/checkers/ConfigImpactAnalysis.ml +++ b/infer/src/checkers/ConfigImpactAnalysis.ml @@ -84,6 +84,9 @@ module UncheckedCallees = struct let replace_location_by_call location x = map (UncheckedCallee.replace_location_by_call location) x + + + let encode astate = Marshal.to_string astate [] |> Base64.encode_exn end module Loc = struct @@ -130,6 +133,9 @@ module Summary = struct let pp f {unchecked_callees; has_call_stmt} = F.fprintf f "@[unchecked callees:@,%a,has_call_stmt:%b@]" UncheckedCallees.pp unchecked_callees has_call_stmt + + + let get_unchecked_callees {unchecked_callees} = unchecked_callees end module Dom = struct diff --git a/infer/src/checkers/ConfigImpactAnalysis.mli b/infer/src/checkers/ConfigImpactAnalysis.mli index 4aa985eb1..661020c0c 100644 --- a/infer/src/checkers/ConfigImpactAnalysis.mli +++ b/infer/src/checkers/ConfigImpactAnalysis.mli @@ -7,10 +7,18 @@ open! IStd +module UncheckedCallees : sig + type t + + val encode : t -> string +end + module Summary : sig type t val pp : Format.formatter -> t -> unit + + val get_unchecked_callees : t -> UncheckedCallees.t end val checker : Summary.t InterproceduralAnalysis.t -> Summary.t option diff --git a/infer/src/integration/Driver.ml b/infer/src/integration/Driver.ml index f84604c74..6dca609c2 100644 --- a/infer/src/integration/Driver.ml +++ b/infer/src/integration/Driver.ml @@ -184,7 +184,9 @@ let execute_analyze_json () = let report ?(suppress_console = false) () = let issues_json = ResultsDir.get_path ReportJson in - JsonReports.write_reports ~issues_json ~costs_json:(ResultsDir.get_path ReportCostsJson) ; + let costs_json = ResultsDir.get_path ReportCostsJson in + let config_impact_json = ResultsDir.get_path ReportConfigImpactJson in + JsonReports.write_reports ~issues_json ~costs_json ~config_impact_json ; (* Post-process the report according to the user config. By default, calls report.py to create a human-readable report. diff --git a/infer/src/integration/JsonReports.ml b/infer/src/integration/JsonReports.ml index b5039c48c..a6bee04cc 100644 --- a/infer/src/integration/JsonReports.ml +++ b/infer/src/integration/JsonReports.ml @@ -304,6 +304,27 @@ end module JsonCostsPrinter = MakeJsonListPrinter (JsonCostsPrinterElt) +module JsonConfigImpactPrinterElt = struct + type elt = + { loc: Location.t + ; proc_name: Procname.t + ; config_impact_opt: ConfigImpactAnalysis.Summary.t option } + + let to_string {loc; proc_name; config_impact_opt} = + Option.map config_impact_opt ~f:(fun config_impact -> + let {NoQualifierHashProcInfo.hash; loc; procedure_name; procedure_id} = + NoQualifierHashProcInfo.get loc proc_name + in + let unchecked_callees = + ConfigImpactAnalysis.Summary.get_unchecked_callees config_impact + |> ConfigImpactAnalysis.UncheckedCallees.encode + in + Jsonbug_j.string_of_config_impact_item + {Jsonbug_t.hash; loc; procedure_name; procedure_id; unchecked_callees} ) +end + +module JsonConfigImpactPrinter = MakeJsonListPrinter (JsonConfigImpactPrinterElt) + let mk_error_filter filters proc_name file error_name = (Config.write_html || not (IssueType.(equal skip_function) error_name)) && filters.Inferconfig.path_filter file @@ -322,24 +343,34 @@ let write_costs proc_name loc cost_opt (outfile : Utils.outfile) = JsonCostsPrinter.pp outfile.fmt {loc; proc_name; cost_opt} +let write_config_impact proc_name loc config_impact_opt (outfile : Utils.outfile) = + if ExternalConfigImpactData.is_in_config_data_file proc_name then + JsonConfigImpactPrinter.pp outfile.fmt {loc; proc_name; config_impact_opt} + + (** Process lint issues of a procedure *) let write_lint_issues filters (issues_outf : Utils.outfile) linereader procname error_log = let error_filter = mk_error_filter filters procname in IssuesJson.pp_issues_of_error_log issues_outf.fmt error_filter linereader None procname error_log -(** Process a summary *) -let process_summary proc_name loc ~cost:(cost_opt, costs_outf) err_log issues_acc = +let process_summary proc_name loc ~cost:(cost_opt, costs_outf) + ~config_impact:(config_impact_opt, config_impact_outf) err_log issues_acc = write_costs proc_name loc cost_opt costs_outf ; + write_config_impact proc_name loc config_impact_opt config_impact_outf ; collect_issues proc_name loc err_log issues_acc -let process_all_summaries_and_issues ~issues_outf ~costs_outf = +let process_all_summaries_and_issues ~issues_outf ~costs_outf ~config_impact_outf = let linereader = LineReader.create () in let filters = Inferconfig.create_filters () in let all_issues = ref [] in - Summary.OnDisk.iter_report_summaries_from_config ~f:(fun proc_name loc cost_opt err_log -> - all_issues := process_summary proc_name loc ~cost:(cost_opt, costs_outf) err_log !all_issues ) ; + Summary.OnDisk.iter_report_summaries_from_config + ~f:(fun proc_name loc cost_opt config_impact_opt err_log -> + all_issues := + process_summary proc_name loc ~cost:(cost_opt, costs_outf) + ~config_impact:(config_impact_opt, config_impact_outf) + err_log !all_issues ) ; all_issues := Issue.sort_filter_issues !all_issues ; List.iter ~f:(fun {Issue.proc_name; proc_location; err_key; err_data} -> @@ -353,7 +384,7 @@ let process_all_summaries_and_issues ~issues_outf ~costs_outf = () -let write_reports ~issues_json ~costs_json = +let write_reports ~issues_json ~costs_json ~config_impact_json = let mk_outfile fname = match Utils.create_outfile fname with | None -> @@ -372,6 +403,8 @@ let write_reports ~issues_json ~costs_json = in let issues_outf = open_outfile_and_fmt issues_json in let costs_outf = open_outfile_and_fmt costs_json in - process_all_summaries_and_issues ~issues_outf ~costs_outf ; + let config_impact_outf = open_outfile_and_fmt config_impact_json in + process_all_summaries_and_issues ~issues_outf ~costs_outf ~config_impact_outf ; + close_fmt_and_outfile config_impact_outf ; close_fmt_and_outfile costs_outf ; close_fmt_and_outfile issues_outf diff --git a/infer/src/integration/JsonReports.mli b/infer/src/integration/JsonReports.mli index 492426f7c..736a483f6 100644 --- a/infer/src/integration/JsonReports.mli +++ b/infer/src/integration/JsonReports.mli @@ -14,4 +14,4 @@ val loc_trace_to_jsonbug_record : val censored_reason : IssueType.t -> SourceFile.t -> string option -val write_reports : issues_json:string -> costs_json:string -> unit +val write_reports : issues_json:string -> costs_json:string -> config_impact_json:string -> unit diff --git a/infer/src/integration/dune.in b/infer/src/integration/dune.in index 45e2215f2..200d09b69 100644 --- a/infer/src/integration/dune.in +++ b/infer/src/integration/dune.in @@ -16,9 +16,9 @@ let library = (flags (:standard -open Core -open IStdlib -open IStd -open OpenSource -open ATDGenerated - -open IBase -open IR -open Absint -open BO -open Costlib -open Concurrency -open Backend + -open IBase -open IR -open Absint -open BO -open Checkers -open Costlib -open Concurrency -open Backend -open TestDeterminators -open ClangFrontend -open ASTLanguage -open JavaFrontend %s %s)) - (libraries xmlm core IStdlib ATDGenerated IBase IR Absint BO Costlib Concurrency Backend + (libraries xmlm core IStdlib ATDGenerated IBase IR Absint BO Checkers Costlib Concurrency Backend TestDeterminators ClangFrontend ASTLanguage JavaFrontend) (preprocess (pps ppx_compare)) )