-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Expand file tree
/
Copy pathregisterCheckers.ml
More file actions
273 lines (246 loc) · 11.1 KB
/
Copy pathregisterCheckers.ml
File metadata and controls
273 lines (246 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
(*
* 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 for registering checkers. *)
module F = Format
type callback_fun =
| Procedure of Callbacks.proc_callback_t
| ProcedureWithSpecialization of
{ procedure_cb: Callbacks.proc_callback_with_specialization_t
; is_already_specialized: Specialization.t -> Summary.t -> bool }
| File of Callbacks.file_callback_t
let interprocedural payload_field checker =
Procedure (CallbackOfChecker.interprocedural_with_field payload_field checker)
let interprocedural_with_specialization payload_field checker is_already_specialized =
ProcedureWithSpecialization
{ procedure_cb=
CallbackOfChecker.interprocedural_with_field_and_specialization payload_field checker
; is_already_specialized=
CallbackOfChecker.make_is_already_specialized_test payload_field is_already_specialized }
let interprocedural_with_field_dependency ~dep_field payload_field checker =
Procedure
(CallbackOfChecker.interprocedural_with_field_dependency ~dep_field payload_field checker)
(** For checkers that read two separate payloads. Assumes that [checker] produces payloads for
[payload_field1] *)
let interprocedural2 payload_field1 payload_field2 checker =
Procedure
(CallbackOfChecker.interprocedural
(Payloads.analysis_request_of_field payload_field1)
~f_analyze_dep:Option.some
~get_payload:(fun payloads ->
( Field.get payload_field1 payloads |> SafeLazy.force_option
, Field.get payload_field2 payloads |> SafeLazy.force_option ) )
~set_payload:(fun payloads payload1 -> Field.fset payload_field1 payloads payload1)
checker )
(** For checkers that read three separate payloads. *)
let interprocedural3 ?checker_without_payload payload_field1 payload_field2 payload_field3
~set_payload checker =
let analysis_req =
(* Use the first payload [payload_field1] as [analysis_req], similar to the other constructs,
unless the optional [checker_without_payload] value is explicitly given. *)
match checker_without_payload with
| None ->
Payloads.analysis_request_of_field payload_field1
| Some checker ->
AnalysisRequest.checker_without_payload checker
in
Procedure
(CallbackOfChecker.interprocedural analysis_req ~f_analyze_dep:Option.some
~get_payload:(fun payloads ->
( Field.get payload_field1 payloads |> SafeLazy.force_option
, Field.get payload_field2 payloads |> SafeLazy.force_option
, Field.get payload_field3 payloads |> SafeLazy.force_option ) )
~set_payload checker )
let file payload_field checker = File (CallbackOfChecker.interprocedural_file payload_field checker)
let intraprocedural checker = Procedure (CallbackOfChecker.intraprocedural checker)
let intraprocedural_with_field_dependency payload_field checker =
Procedure (CallbackOfChecker.intraprocedural_with_field_dependency payload_field checker)
type checker = {checker: Checker.t; callbacks: (callback_fun * Language.t) list}
let all_checkers =
(* The order of the list is important for those checkers that depend on other checkers having run
before them. *)
[ {checker= SelfInBlock; callbacks= [(intraprocedural SelfInBlock.checker, Clang)]}
; { checker= ParameterNotNullChecked
; callbacks= [(intraprocedural ParameterNotNullChecked.checker, Clang)] }
; { checker= StaticConstructorStallChecker
; callbacks=
[ ( interprocedural Payloads.Fields.static_constructor_stall_checker
StaticConstructorStallChecker.checker
, Clang ) ] }
; { checker= BufferOverrunAnalysis
; callbacks=
(let bo_analysis =
interprocedural Payloads.Fields.buffer_overrun_analysis
BufferOverrunAnalysis.analyze_procedure
in
[(bo_analysis, Clang); (bo_analysis, Java)] ) }
; { checker= BufferOverrunChecker
; callbacks=
(let bo_checker =
interprocedural2 Payloads.Fields.buffer_overrun_checker
Payloads.Fields.buffer_overrun_analysis BufferOverrunChecker.checker
in
[(bo_checker, Clang); (bo_checker, Java)] ) }
; { checker= PurityAnalysis
; callbacks=
(let purity =
interprocedural2 Payloads.Fields.purity Payloads.Fields.buffer_overrun_analysis
PurityAnalysis.checker
in
[(purity, Java); (purity, Clang)] ) }
; { checker= PurityChecker
; callbacks=
(let purity =
intraprocedural_with_field_dependency Payloads.Fields.purity PurityChecker.checker
in
[(purity, Java); (purity, Clang)] ) }
; { checker= Starvation
; callbacks=
(let starvation = interprocedural Payloads.Fields.starvation Starvation.analyze_procedure in
let starvation_file_reporting = file Payloads.Fields.starvation Starvation.reporting in
[ (starvation, Java)
; (starvation_file_reporting, Java)
; (starvation, Clang)
; (starvation_file_reporting, Clang) ] ) }
; { checker= LoopHoisting
; callbacks=
(let hoisting =
interprocedural3 ~checker_without_payload:LoopHoisting
~set_payload:(fun payloads (_ : unit SafeLazy.t option) ->
(* this analysis doesn't produce additional payloads *) payloads )
Payloads.Fields.buffer_overrun_analysis Payloads.Fields.purity Payloads.Fields.cost
(fun analysis_data -> Some (Hoisting.checker analysis_data))
in
[(hoisting, Clang); (hoisting, Java)] ) }
; { checker= Cost
; callbacks=
(let checker =
interprocedural3 ~set_payload:(Field.fset Payloads.Fields.cost) Payloads.Fields.cost
Payloads.Fields.buffer_overrun_analysis Payloads.Fields.purity Cost.checker
in
[(checker, Clang); (checker, Java); (checker, Hack)] ) }
; {checker= SIOF; callbacks= [(interprocedural Payloads.Fields.siof Siof.checker, Clang)]}
; { checker= LithoRequiredProps
; callbacks= [(interprocedural Payloads.Fields.litho_required_props RequiredProps.checker, Java)]
}
; (* toy resource analysis to use in the infer lab, see the lab/ directory *)
{ checker= ResourceLeakLabExercise
; callbacks=
[ ( (* the checked-in version is intraprocedural, but the lab asks to make it
interprocedural later on *)
interprocedural Payloads.Fields.lab_resource_leaks ResourceLeaks.checker
, Java ) ] }
; { checker= RacerD
; callbacks=
(let racerd_proc = interprocedural Payloads.Fields.racerd RacerDProcAnalysis.analyze in
let racerd_file = file Payloads.Fields.racerd RacerDFileAnalysis.analyze in
[ (racerd_proc, Clang)
; (racerd_proc, Java)
; (racerd_proc, CIL)
; (racerd_file, Clang)
; (racerd_file, Java)
; (racerd_file, CIL) ] ) }
; { checker= DisjunctiveDemo
; callbacks= [(interprocedural Payloads.Fields.disjunctive_demo DisjunctiveDemo.checker, Clang)]
}
; { checker= Pulse
; callbacks=
(let pulse =
interprocedural_with_specialization Payloads.Fields.pulse Pulse.checker
Pulse.is_already_specialized
in
[ (pulse, Clang)
; (pulse, Erlang)
; (pulse, Hack)
; (pulse, Java)
; (pulse, CIL)
; (pulse, Python)
; (pulse, Rust)
; (pulse, Swift) ] ) }
; { checker= Impurity
; callbacks=
(let impurity =
intraprocedural_with_field_dependency Payloads.Fields.pulse Impurity.checker
in
[(impurity, Java); (impurity, Clang); (impurity, Hack)] ) }
; {checker= Liveness; callbacks= [(intraprocedural Liveness.checker, Clang)]}
; { checker= InefficientKeysetIterator
; callbacks= [(intraprocedural InefficientKeysetIterator.checker, Java)] }
; { checker= FragmentRetainsView
; callbacks= [(intraprocedural FragmentRetainsViewChecker.callback_fragment_retains_view, Java)]
}
; { checker= AnnotationReachability
; callbacks=
(let annot_reach =
interprocedural Payloads.Fields.annot_map AnnotationReachability.checker
in
[(annot_reach, Clang); (annot_reach, Erlang); (annot_reach, Java); (annot_reach, Swift)] )
}
; { checker= ConfigGating
; callbacks=
(let checker = intraprocedural ConfigGating.checker in
[(checker, Clang); (checker, Java)] ) }
; { checker= ConfigImpactAnalysis
; callbacks=
(let checker =
interprocedural Payloads.Fields.config_impact_analysis ConfigImpactAnalysis.checker
in
[(checker, Clang); (checker, Java)] ) }
; { checker= LineageShape
; callbacks=
(let checker = interprocedural Payloads.Fields.lineage_shape LineageShape.checker in
[(checker, Erlang)] ) }
; { checker= Lineage
; callbacks=
(let checker =
interprocedural_with_field_dependency ~dep_field:Payloads.Fields.lineage_shape
Payloads.Fields.lineage Lineage.checker
in
[(checker, Erlang)] ) }
; { checker= ScopeLeakage
; callbacks=
(let checker = interprocedural Payloads.Fields.scope_leakage ScopeLeakage.checker in
[(checker, Java)] ) }
; { checker= SILValidation
; callbacks=
(let java_validator = intraprocedural (SilValidation.checker Language.Java) in
let clang_validator = intraprocedural (SilValidation.checker Language.Clang) in
let erlang_validator = intraprocedural (SilValidation.checker Language.Erlang) in
[(java_validator, Java); (clang_validator, Clang); (erlang_validator, Erlang)] ) }
; { checker= SwiftObjCNullability
; callbacks= [(intraprocedural SwiftObjCNullabilityChecker.checker, Swift)] } ]
let get_active_checkers () =
let filter_checker {checker} = Config.is_checker_enabled checker in
List.filter ~f:filter_checker all_checkers
let register checkers =
let register_one {checker; callbacks} =
Logging.debug Analysis Verbose "Register checker %s that depends on %a.@."
(Checker.get_id checker) Checker.Set.pp
(Checker.get_dependencies checker) ;
let register_callback (callback, language) =
match callback with
| Procedure procedure_cb ->
Callbacks.register_procedure_callback checker language procedure_cb
| ProcedureWithSpecialization {procedure_cb; is_already_specialized} ->
Callbacks.register_procedure_callback_with_specialization checker language procedure_cb
~is_already_specialized
| File callback ->
Callbacks.register_file_callback checker language callback
in
List.iter ~f:register_callback callbacks
in
List.iter ~f:register_one checkers
module LanguageSet = Stdlib.Set.Make (Language)
let pp_checker fmt {checker; callbacks} =
let langs_of_callbacks =
List.fold_left callbacks ~init:LanguageSet.empty ~f:(fun langs (_, lang) ->
LanguageSet.add lang langs )
|> LanguageSet.elements
in
F.fprintf fmt "%s (%a)" (Checker.get_id checker)
(Pp.seq ~sep:", " (Pp.of_string ~f:Language.to_string))
langs_of_callbacks