From 4b3dd96fcaeef8fbd8aa20895dec01d36d60da3f Mon Sep 17 00:00:00 2001 From: Dulma Churchill Date: Tue, 26 Nov 2024 06:23:36 -0800 Subject: [PATCH] [dispatch-once-static-init] Make the checker interprocedural Summary: Made the domain into a summary and added necessary scaffolding to make the checker inter-procedural. We still need to improve the location of the report and add traces, will do in a follow up diff. Reviewed By: skcho Differential Revision: D66456757 Privacy Context Container: L1208441 fbshipit-source-id: 1c695ba11a91d0da2e7147d777b15b04169c1201 --- infer/src/backend/Payloads.ml | 9 +++- infer/src/backend/Payloads.mli | 1 + infer/src/backend/registerCheckers.ml | 4 +- infer/src/base/PayloadId.ml | 3 ++ infer/src/base/PayloadId.mli | 1 + infer/src/checkers/DispatchOnceStaticInit.ml | 42 ++++++++++++------- infer/src/checkers/DispatchOnceStaticInit.mli | 20 +++++++++ .../DispatchOnceInStaticInit.m | 3 +- .../objc/dispatch-once-static-init/issues.exp | 1 + 9 files changed, 63 insertions(+), 21 deletions(-) create mode 100644 infer/src/checkers/DispatchOnceStaticInit.mli diff --git a/infer/src/backend/Payloads.ml b/infer/src/backend/Payloads.ml index fa058b87de6..fc0d41a0ef2 100644 --- a/infer/src/backend/Payloads.ml +++ b/infer/src/backend/Payloads.ml @@ -17,6 +17,7 @@ type t = ; config_impact_analysis: ConfigImpactAnalysis.Summary.t Lazy.t option ; cost: CostDomain.summary Lazy.t option ; disjunctive_demo: DisjunctiveDemo.domain Lazy.t option + ; dispatch_once_static_init: DispatchOnceStaticInit.Summary.t Lazy.t option ; lab_resource_leaks: ResourceLeakDomain.summary Lazy.t option ; litho_required_props: LithoDomain.summary Lazy.t option ; pulse: PulseSummary.t Lazy.t option @@ -64,6 +65,7 @@ let all_fields = ~config_impact_analysis:(fun f -> mk f ConfigImpactAnalysis ConfigImpactAnalysis.Summary.pp) ~cost:(fun f -> mk f Cost CostDomain.pp_summary) ~disjunctive_demo:(fun f -> mk f DisjunctiveDemo DisjunctiveDemo.pp_domain) + ~dispatch_once_static_init:(fun f -> mk f DisjunctiveDemo DispatchOnceStaticInit.Summary.pp) ~litho_required_props:(fun f -> mk f LithoRequiredProps LithoDomain.pp_summary) ~pulse:(fun f -> mk_full f Pulse PulseSummary.pp) ~purity:(fun f -> mk f Purity PurityDomain.pp_summary) @@ -108,6 +110,7 @@ let empty = ; config_impact_analysis= None ; cost= None ; disjunctive_demo= None + ; dispatch_once_static_init= None ; lab_resource_leaks= None ; litho_required_props= None ; pulse= None @@ -206,8 +209,9 @@ module SQLite = struct Fields.make_creator ~annot_map:data_of_sqlite_column ~biabduction:data_of_sqlite_column ~buffer_overrun_analysis:data_of_sqlite_column ~buffer_overrun_checker:data_of_sqlite_column ~config_impact_analysis:data_of_sqlite_column ~cost:data_of_sqlite_column - ~disjunctive_demo:data_of_sqlite_column ~litho_required_props:data_of_sqlite_column - ~pulse:data_of_sqlite_column ~purity:data_of_sqlite_column ~racerd:data_of_sqlite_column + ~disjunctive_demo:data_of_sqlite_column ~dispatch_once_static_init:data_of_sqlite_column + ~litho_required_props:data_of_sqlite_column ~pulse:data_of_sqlite_column + ~purity:data_of_sqlite_column ~racerd:data_of_sqlite_column ~lab_resource_leaks:data_of_sqlite_column ~scope_leakage:data_of_sqlite_column ~siof:data_of_sqlite_column ~lineage:data_of_sqlite_column ~lineage_shape:data_of_sqlite_column ~starvation:data_of_sqlite_column @@ -257,6 +261,7 @@ module SQLite = struct ; config_impact_analysis= load table ~proc_uid ConfigImpactAnalysis ; cost= load table ~proc_uid Cost ; disjunctive_demo= load table ~proc_uid DisjunctiveDemo + ; dispatch_once_static_init= load table ~proc_uid DispatchOnceStaticInit ; lab_resource_leaks= load table ~proc_uid LabResourceLeaks ; litho_required_props= load table ~proc_uid LithoRequiredProps ; pulse= load table ~proc_uid Pulse diff --git a/infer/src/backend/Payloads.mli b/infer/src/backend/Payloads.mli index c98bda80d0a..64eb308271d 100644 --- a/infer/src/backend/Payloads.mli +++ b/infer/src/backend/Payloads.mli @@ -26,6 +26,7 @@ include sig ; config_impact_analysis: ConfigImpactAnalysis.Summary.t Lazy.t option ; cost: CostDomain.summary Lazy.t option ; disjunctive_demo: DisjunctiveDemo.domain Lazy.t option + ; dispatch_once_static_init: DispatchOnceStaticInit.Summary.t Lazy.t option ; lab_resource_leaks: ResourceLeakDomain.summary Lazy.t option ; litho_required_props: LithoDomain.summary Lazy.t option ; pulse: PulseSummary.t Lazy.t option diff --git a/infer/src/backend/registerCheckers.ml b/infer/src/backend/registerCheckers.ml index a1933532927..abc6b0e295d 100644 --- a/infer/src/backend/registerCheckers.ml +++ b/infer/src/backend/registerCheckers.ml @@ -92,7 +92,9 @@ let all_checkers = ; { checker= ParameterNotNullChecked ; callbacks= [(intraprocedural ParameterNotNullChecked.checker, Clang)] } ; { checker= DispatchOnceStaticInit - ; callbacks= [(intraprocedural DispatchOnceStaticInit.checker, Clang)] } + ; callbacks= + [ ( interprocedural Payloads.Fields.dispatch_once_static_init DispatchOnceStaticInit.checker + , Clang ) ] } ; { checker= BufferOverrunAnalysis ; callbacks= (let bo_analysis = diff --git a/infer/src/base/PayloadId.ml b/infer/src/base/PayloadId.ml index 746616c117f..94050f5b638 100644 --- a/infer/src/base/PayloadId.ml +++ b/infer/src/base/PayloadId.ml @@ -15,6 +15,7 @@ type t = | ConfigImpactAnalysis | Cost | DisjunctiveDemo + | DispatchOnceStaticInit | LabResourceLeaks | LithoRequiredProps | Pulse @@ -45,6 +46,8 @@ let to_checker payload_id : Checker.t = Cost | DisjunctiveDemo -> DisjunctiveDemo + | DispatchOnceStaticInit -> + DispatchOnceStaticInit | LabResourceLeaks -> ResourceLeakLabExercise | LithoRequiredProps -> diff --git a/infer/src/base/PayloadId.mli b/infer/src/base/PayloadId.mli index eeda45e0ab5..7097df0fd0c 100644 --- a/infer/src/base/PayloadId.mli +++ b/infer/src/base/PayloadId.mli @@ -16,6 +16,7 @@ type t = | ConfigImpactAnalysis | Cost | DisjunctiveDemo + | DispatchOnceStaticInit | LabResourceLeaks | LithoRequiredProps | Pulse diff --git a/infer/src/checkers/DispatchOnceStaticInit.ml b/infer/src/checkers/DispatchOnceStaticInit.ml index f67db7504d3..5e160ffe349 100644 --- a/infer/src/checkers/DispatchOnceStaticInit.ml +++ b/infer/src/checkers/DispatchOnceStaticInit.ml @@ -13,25 +13,33 @@ module Mem = struct let pp fmt {loc} = F.fprintf fmt "calls_dispatch_once at %a" Location.pp loc end -module Domain = struct +module Summary = struct include AbstractDomain.FiniteSet (Mem) let add_calls_dispatch_once loc astate = add {Mem.loc} astate end module TransferFunctions = struct - module Domain = Domain + module Domain = Summary module CFG = ProcCfg.Normal - type analysis_data = IntraproceduralAnalysis.t + type analysis_data = Summary.t InterproceduralAnalysis.t let pp_session_name _node fmt = F.pp_print_string fmt "DispatchOnceStaticInit" - let exec_instr (astate : Domain.t) _ _cfg_node _ (instr : Sil.instr) = + let exec_instr (astate : Summary.t) {InterproceduralAnalysis.analyze_dependency} _cfg_node _ + (instr : Sil.instr) = match instr with | Call (_, Exp.Const (Const.Cfun procname), _, loc, _) -> + let astate = + match analyze_dependency procname with + | Ok summary -> + Summary.join astate summary + | Error _ -> + astate + in let calls_dispatch_once = String.equal "_dispatch_once" (Procname.get_method procname) in - if calls_dispatch_once then Domain.add_calls_dispatch_once loc astate else astate + if calls_dispatch_once then Summary.add_calls_dispatch_once loc astate else astate | _ -> astate end @@ -55,16 +63,18 @@ let report_issue proc_desc err_log {Mem.loc} = IssueType.dispatch_once_in_static_init message -let checker ({IntraproceduralAnalysis.proc_desc; err_log} as analysis_data) = +let checker ({InterproceduralAnalysis.proc_desc; err_log} as analysis_data) = let attributes = Procdesc.get_attributes proc_desc in - if attributes.ProcAttributes.is_static_ctor then - let initial = Domain.empty in - match Analyzer.compute_post analysis_data ~initial proc_desc with - | Some domain -> ( - match Domain.choose_opt domain with - | Some mem -> - report_issue proc_desc err_log mem + let initial = Summary.empty in + let summary_opt = Analyzer.compute_post analysis_data ~initial proc_desc in + ( if attributes.ProcAttributes.is_static_ctor then + match summary_opt with + | Some domain -> ( + match Summary.choose_opt domain with + | Some mem -> + report_issue proc_desc err_log mem + | None -> + () ) | None -> - () ) - | None -> - () + () ) ; + summary_opt diff --git a/infer/src/checkers/DispatchOnceStaticInit.mli b/infer/src/checkers/DispatchOnceStaticInit.mli new file mode 100644 index 00000000000..d4965c7cca6 --- /dev/null +++ b/infer/src/checkers/DispatchOnceStaticInit.mli @@ -0,0 +1,20 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) +open! IStd +module F = Format + +module Mem : sig + type t = {loc: Location.t} + + val compare : t -> t -> int + + val pp : F.formatter -> t -> unit +end + +module Summary : module type of AbstractDomain.FiniteSet (Mem) + +val checker : Summary.t InterproceduralAnalysis.t -> Summary.t option diff --git a/infer/tests/codetoanalyze/objc/dispatch-once-static-init/DispatchOnceInStaticInit.m b/infer/tests/codetoanalyze/objc/dispatch-once-static-init/DispatchOnceInStaticInit.m index e23844b6742..a66e59f8fd3 100644 --- a/infer/tests/codetoanalyze/objc/dispatch-once-static-init/DispatchOnceInStaticInit.m +++ b/infer/tests/codetoanalyze/objc/dispatch-once-static-init/DispatchOnceInStaticInit.m @@ -23,8 +23,7 @@ + (instancetype)getInstance { @end -__attribute__((constructor)) static void initializer_test_interproc_bad_FN( - void) { +__attribute__((constructor)) static void initializer_test_interproc_bad(void) { [Manager getInstance]; } diff --git a/infer/tests/codetoanalyze/objc/dispatch-once-static-init/issues.exp b/infer/tests/codetoanalyze/objc/dispatch-once-static-init/issues.exp index 5c5296aa8f7..856ef24b39c 100644 --- a/infer/tests/codetoanalyze/objc/dispatch-once-static-init/issues.exp +++ b/infer/tests/codetoanalyze/objc/dispatch-once-static-init/issues.exp @@ -1 +1,2 @@ +codetoanalyze/objc/dispatch-once-static-init/DispatchOnceInStaticInit.m, initializer_test_interproc_bad, -8, DISPATCH_ONCE_IN_STATIC_INIT, no_bucket, ERROR, [macro expanded here,Call to `dispatch_once` here] codetoanalyze/objc/dispatch-once-static-init/DispatchOnceInStaticInit.m, initializer_test_intraproc_bad, 3, DISPATCH_ONCE_IN_STATIC_INIT, no_bucket, ERROR, [macro expanded here,Call to `dispatch_once` here]