Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===- CheckerManager.h - Static Analyzer Checker Manager -------*- C++ -*-===// |
2 | // |
||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
4 | // See https://llvm.org/LICENSE.txt for license information. |
||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
6 | // |
||
7 | //===----------------------------------------------------------------------===// |
||
8 | // |
||
9 | // Defines the Static Analyzer Checker Manager. |
||
10 | // |
||
11 | //===----------------------------------------------------------------------===// |
||
12 | |||
13 | #ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H |
||
14 | #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H |
||
15 | |||
16 | #include "clang/Analysis/ProgramPoint.h" |
||
17 | #include "clang/Basic/Diagnostic.h" |
||
18 | #include "clang/Basic/LangOptions.h" |
||
19 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" |
||
20 | #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" |
||
21 | #include "llvm/ADT/ArrayRef.h" |
||
22 | #include "llvm/ADT/DenseMap.h" |
||
23 | #include "llvm/ADT/SmallVector.h" |
||
24 | #include "llvm/ADT/StringRef.h" |
||
25 | #include <vector> |
||
26 | |||
27 | namespace clang { |
||
28 | |||
29 | class AnalyzerOptions; |
||
30 | class CallExpr; |
||
31 | class Decl; |
||
32 | class LocationContext; |
||
33 | class Stmt; |
||
34 | class TranslationUnitDecl; |
||
35 | |||
36 | namespace ento { |
||
37 | |||
38 | class AnalysisManager; |
||
39 | class CXXAllocatorCall; |
||
40 | class BugReporter; |
||
41 | class CallEvent; |
||
42 | class CheckerBase; |
||
43 | class CheckerContext; |
||
44 | class CheckerRegistry; |
||
45 | struct CheckerRegistryData; |
||
46 | class ExplodedGraph; |
||
47 | class ExplodedNode; |
||
48 | class ExplodedNodeSet; |
||
49 | class ExprEngine; |
||
50 | struct EvalCallOptions; |
||
51 | class MemRegion; |
||
52 | struct NodeBuilderContext; |
||
53 | class ObjCMethodCall; |
||
54 | class RegionAndSymbolInvalidationTraits; |
||
55 | class SVal; |
||
56 | class SymbolReaper; |
||
57 | |||
58 | template <typename T> class CheckerFn; |
||
59 | |||
60 | template <typename RET, typename... Ps> |
||
61 | class CheckerFn<RET(Ps...)> { |
||
62 | using Func = RET (*)(void *, Ps...); |
||
63 | |||
64 | Func Fn; |
||
65 | |||
66 | public: |
||
67 | CheckerBase *Checker; |
||
68 | |||
69 | CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) {} |
||
70 | |||
71 | RET operator()(Ps... ps) const { |
||
72 | return Fn(Checker, ps...); |
||
73 | } |
||
74 | }; |
||
75 | |||
76 | /// Describes the different reasons a pointer escapes |
||
77 | /// during analysis. |
||
78 | enum PointerEscapeKind { |
||
79 | /// A pointer escapes due to binding its value to a location |
||
80 | /// that the analyzer cannot track. |
||
81 | PSK_EscapeOnBind, |
||
82 | |||
83 | /// The pointer has been passed to a function call directly. |
||
84 | PSK_DirectEscapeOnCall, |
||
85 | |||
86 | /// The pointer has been passed to a function indirectly. |
||
87 | /// For example, the pointer is accessible through an |
||
88 | /// argument to a function. |
||
89 | PSK_IndirectEscapeOnCall, |
||
90 | |||
91 | |||
92 | /// Escape for a new symbol that was generated into a region |
||
93 | /// that the analyzer cannot follow during a conservative call. |
||
94 | PSK_EscapeOutParameters, |
||
95 | |||
96 | /// The reason for pointer escape is unknown. For example, |
||
97 | /// a region containing this pointer is invalidated. |
||
98 | PSK_EscapeOther |
||
99 | }; |
||
100 | |||
101 | /// This wrapper is used to ensure that only StringRefs originating from the |
||
102 | /// CheckerRegistry are used as check names. We want to make sure all checker |
||
103 | /// name strings have a lifetime that keeps them alive at least until the path |
||
104 | /// diagnostics have been processed, since they are expected to be constexpr |
||
105 | /// string literals (most likely generated by TblGen). |
||
106 | class CheckerNameRef { |
||
107 | friend class ::clang::ento::CheckerRegistry; |
||
108 | |||
109 | StringRef Name; |
||
110 | |||
111 | explicit CheckerNameRef(StringRef Name) : Name(Name) {} |
||
112 | |||
113 | public: |
||
114 | CheckerNameRef() = default; |
||
115 | |||
116 | StringRef getName() const { return Name; } |
||
117 | operator StringRef() const { return Name; } |
||
118 | }; |
||
119 | |||
120 | enum class ObjCMessageVisitKind { |
||
121 | Pre, |
||
122 | Post, |
||
123 | MessageNil |
||
124 | }; |
||
125 | |||
126 | class CheckerManager { |
||
127 | ASTContext *Context = nullptr; |
||
128 | const LangOptions LangOpts; |
||
129 | const AnalyzerOptions &AOptions; |
||
130 | const Preprocessor *PP = nullptr; |
||
131 | CheckerNameRef CurrentCheckerName; |
||
132 | DiagnosticsEngine &Diags; |
||
133 | std::unique_ptr<CheckerRegistryData> RegistryData; |
||
134 | |||
135 | public: |
||
136 | // These constructors are defined in the Frontend library, because |
||
137 | // CheckerRegistry, a crucial component of the initialization is in there. |
||
138 | // CheckerRegistry cannot be moved to the Core library, because the checker |
||
139 | // registration functions are defined in the Checkers library, and the library |
||
140 | // dependencies look like this: Core -> Checkers -> Frontend. |
||
141 | |||
142 | CheckerManager( |
||
143 | ASTContext &Context, AnalyzerOptions &AOptions, const Preprocessor &PP, |
||
144 | ArrayRef<std::string> plugins, |
||
145 | ArrayRef<std::function<void(CheckerRegistry &)>> checkerRegistrationFns); |
||
146 | |||
147 | /// Constructs a CheckerManager that ignores all non TblGen-generated |
||
148 | /// checkers. Useful for unit testing, unless the checker infrastructure |
||
149 | /// itself is tested. |
||
150 | CheckerManager(ASTContext &Context, AnalyzerOptions &AOptions, |
||
151 | const Preprocessor &PP) |
||
152 | : CheckerManager(Context, AOptions, PP, {}, {}) {} |
||
153 | |||
154 | /// Constructs a CheckerManager without requiring an AST. No checker |
||
155 | /// registration will take place. Only useful when one needs to print the |
||
156 | /// help flags through CheckerRegistryData, and the AST is unavailable. |
||
157 | CheckerManager(AnalyzerOptions &AOptions, const LangOptions &LangOpts, |
||
158 | DiagnosticsEngine &Diags, ArrayRef<std::string> plugins); |
||
159 | |||
160 | ~CheckerManager(); |
||
161 | |||
162 | void setCurrentCheckerName(CheckerNameRef name) { CurrentCheckerName = name; } |
||
163 | CheckerNameRef getCurrentCheckerName() const { return CurrentCheckerName; } |
||
164 | |||
165 | bool hasPathSensitiveCheckers() const; |
||
166 | |||
167 | void finishedCheckerRegistration(); |
||
168 | |||
169 | const LangOptions &getLangOpts() const { return LangOpts; } |
||
170 | const AnalyzerOptions &getAnalyzerOptions() const { return AOptions; } |
||
171 | const Preprocessor &getPreprocessor() const { |
||
172 | assert(PP); |
||
173 | return *PP; |
||
174 | } |
||
175 | const CheckerRegistryData &getCheckerRegistryData() const { |
||
176 | return *RegistryData; |
||
177 | } |
||
178 | DiagnosticsEngine &getDiagnostics() const { return Diags; } |
||
179 | ASTContext &getASTContext() const { |
||
180 | assert(Context); |
||
181 | return *Context; |
||
182 | } |
||
183 | |||
184 | /// Emits an error through a DiagnosticsEngine about an invalid user supplied |
||
185 | /// checker option value. |
||
186 | void reportInvalidCheckerOptionValue(const CheckerBase *C, |
||
187 | StringRef OptionName, |
||
188 | StringRef ExpectedValueDesc) const; |
||
189 | |||
190 | using CheckerRef = CheckerBase *; |
||
191 | using CheckerTag = const void *; |
||
192 | using CheckerDtor = CheckerFn<void ()>; |
||
193 | |||
194 | //===----------------------------------------------------------------------===// |
||
195 | // Checker registration. |
||
196 | //===----------------------------------------------------------------------===// |
||
197 | |||
198 | /// Used to register checkers. |
||
199 | /// All arguments are automatically passed through to the checker |
||
200 | /// constructor. |
||
201 | /// |
||
202 | /// \returns a pointer to the checker object. |
||
203 | template <typename CHECKER, typename... AT> |
||
204 | CHECKER *registerChecker(AT &&... Args) { |
||
205 | CheckerTag tag = getTag<CHECKER>(); |
||
206 | CheckerRef &ref = CheckerTags[tag]; |
||
207 | assert(!ref && "Checker already registered, use getChecker!"); |
||
208 | |||
209 | CHECKER *checker = new CHECKER(std::forward<AT>(Args)...); |
||
210 | checker->Name = CurrentCheckerName; |
||
211 | CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>)); |
||
212 | CHECKER::_register(checker, *this); |
||
213 | ref = checker; |
||
214 | return checker; |
||
215 | } |
||
216 | |||
217 | template <typename CHECKER> |
||
218 | CHECKER *getChecker() { |
||
219 | CheckerTag tag = getTag<CHECKER>(); |
||
220 | assert(CheckerTags.count(tag) != 0 && |
||
221 | "Requested checker is not registered! Maybe you should add it as a " |
||
222 | "dependency in Checkers.td?"); |
||
223 | return static_cast<CHECKER *>(CheckerTags[tag]); |
||
224 | } |
||
225 | |||
226 | //===----------------------------------------------------------------------===// |
||
227 | // Functions for running checkers for AST traversing. |
||
228 | //===----------------------------------------------------------------------===// |
||
229 | |||
230 | /// Run checkers handling Decls. |
||
231 | void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, |
||
232 | BugReporter &BR); |
||
233 | |||
234 | /// Run checkers handling Decls containing a Stmt body. |
||
235 | void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, |
||
236 | BugReporter &BR); |
||
237 | |||
238 | //===----------------------------------------------------------------------===// |
||
239 | // Functions for running checkers for path-sensitive checking. |
||
240 | //===----------------------------------------------------------------------===// |
||
241 | |||
242 | /// Run checkers for pre-visiting Stmts. |
||
243 | /// |
||
244 | /// The notification is performed for every explored CFGElement, which does |
||
245 | /// not include the control flow statements such as IfStmt. |
||
246 | /// |
||
247 | /// \sa runCheckersForBranchCondition, runCheckersForPostStmt |
||
248 | void runCheckersForPreStmt(ExplodedNodeSet &Dst, |
||
249 | const ExplodedNodeSet &Src, |
||
250 | const Stmt *S, |
||
251 | ExprEngine &Eng) { |
||
252 | runCheckersForStmt(/*isPreVisit=*/true, Dst, Src, S, Eng); |
||
253 | } |
||
254 | |||
255 | /// Run checkers for post-visiting Stmts. |
||
256 | /// |
||
257 | /// The notification is performed for every explored CFGElement, which does |
||
258 | /// not include the control flow statements such as IfStmt. |
||
259 | /// |
||
260 | /// \sa runCheckersForBranchCondition, runCheckersForPreStmt |
||
261 | void runCheckersForPostStmt(ExplodedNodeSet &Dst, |
||
262 | const ExplodedNodeSet &Src, |
||
263 | const Stmt *S, |
||
264 | ExprEngine &Eng, |
||
265 | bool wasInlined = false) { |
||
266 | runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng, wasInlined); |
||
267 | } |
||
268 | |||
269 | /// Run checkers for visiting Stmts. |
||
270 | void runCheckersForStmt(bool isPreVisit, |
||
271 | ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, |
||
272 | const Stmt *S, ExprEngine &Eng, |
||
273 | bool wasInlined = false); |
||
274 | |||
275 | /// Run checkers for pre-visiting obj-c messages. |
||
276 | void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst, |
||
277 | const ExplodedNodeSet &Src, |
||
278 | const ObjCMethodCall &msg, |
||
279 | ExprEngine &Eng) { |
||
280 | runCheckersForObjCMessage(ObjCMessageVisitKind::Pre, Dst, Src, msg, Eng); |
||
281 | } |
||
282 | |||
283 | /// Run checkers for post-visiting obj-c messages. |
||
284 | void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst, |
||
285 | const ExplodedNodeSet &Src, |
||
286 | const ObjCMethodCall &msg, |
||
287 | ExprEngine &Eng, |
||
288 | bool wasInlined = false) { |
||
289 | runCheckersForObjCMessage(ObjCMessageVisitKind::Post, Dst, Src, msg, Eng, |
||
290 | wasInlined); |
||
291 | } |
||
292 | |||
293 | /// Run checkers for visiting an obj-c message to nil. |
||
294 | void runCheckersForObjCMessageNil(ExplodedNodeSet &Dst, |
||
295 | const ExplodedNodeSet &Src, |
||
296 | const ObjCMethodCall &msg, |
||
297 | ExprEngine &Eng) { |
||
298 | runCheckersForObjCMessage(ObjCMessageVisitKind::MessageNil, Dst, Src, msg, |
||
299 | Eng); |
||
300 | } |
||
301 | |||
302 | /// Run checkers for visiting obj-c messages. |
||
303 | void runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, |
||
304 | ExplodedNodeSet &Dst, |
||
305 | const ExplodedNodeSet &Src, |
||
306 | const ObjCMethodCall &msg, ExprEngine &Eng, |
||
307 | bool wasInlined = false); |
||
308 | |||
309 | /// Run checkers for pre-visiting obj-c messages. |
||
310 | void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, |
||
311 | const CallEvent &Call, ExprEngine &Eng) { |
||
312 | runCheckersForCallEvent(/*isPreVisit=*/true, Dst, Src, Call, Eng); |
||
313 | } |
||
314 | |||
315 | /// Run checkers for post-visiting obj-c messages. |
||
316 | void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, |
||
317 | const CallEvent &Call, ExprEngine &Eng, |
||
318 | bool wasInlined = false) { |
||
319 | runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng, |
||
320 | wasInlined); |
||
321 | } |
||
322 | |||
323 | /// Run checkers for visiting obj-c messages. |
||
324 | void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst, |
||
325 | const ExplodedNodeSet &Src, |
||
326 | const CallEvent &Call, ExprEngine &Eng, |
||
327 | bool wasInlined = false); |
||
328 | |||
329 | /// Run checkers for load/store of a location. |
||
330 | void runCheckersForLocation(ExplodedNodeSet &Dst, |
||
331 | const ExplodedNodeSet &Src, |
||
332 | SVal location, |
||
333 | bool isLoad, |
||
334 | const Stmt *NodeEx, |
||
335 | const Stmt *BoundEx, |
||
336 | ExprEngine &Eng); |
||
337 | |||
338 | /// Run checkers for binding of a value to a location. |
||
339 | void runCheckersForBind(ExplodedNodeSet &Dst, |
||
340 | const ExplodedNodeSet &Src, |
||
341 | SVal location, SVal val, |
||
342 | const Stmt *S, ExprEngine &Eng, |
||
343 | const ProgramPoint &PP); |
||
344 | |||
345 | /// Run checkers for end of analysis. |
||
346 | void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, |
||
347 | ExprEngine &Eng); |
||
348 | |||
349 | /// Run checkers on beginning of function. |
||
350 | void runCheckersForBeginFunction(ExplodedNodeSet &Dst, |
||
351 | const BlockEdge &L, |
||
352 | ExplodedNode *Pred, |
||
353 | ExprEngine &Eng); |
||
354 | |||
355 | /// Run checkers on end of function. |
||
356 | void runCheckersForEndFunction(NodeBuilderContext &BC, |
||
357 | ExplodedNodeSet &Dst, |
||
358 | ExplodedNode *Pred, |
||
359 | ExprEngine &Eng, |
||
360 | const ReturnStmt *RS); |
||
361 | |||
362 | /// Run checkers for branch condition. |
||
363 | void runCheckersForBranchCondition(const Stmt *condition, |
||
364 | ExplodedNodeSet &Dst, ExplodedNode *Pred, |
||
365 | ExprEngine &Eng); |
||
366 | |||
367 | /// Run checkers between C++ operator new and constructor calls. |
||
368 | void runCheckersForNewAllocator(const CXXAllocatorCall &Call, |
||
369 | ExplodedNodeSet &Dst, ExplodedNode *Pred, |
||
370 | ExprEngine &Eng, bool wasInlined = false); |
||
371 | |||
372 | /// Run checkers for live symbols. |
||
373 | /// |
||
374 | /// Allows modifying SymbolReaper object. For example, checkers can explicitly |
||
375 | /// register symbols of interest as live. These symbols will not be marked |
||
376 | /// dead and removed. |
||
377 | void runCheckersForLiveSymbols(ProgramStateRef state, |
||
378 | SymbolReaper &SymReaper); |
||
379 | |||
380 | /// Run checkers for dead symbols. |
||
381 | /// |
||
382 | /// Notifies checkers when symbols become dead. For example, this allows |
||
383 | /// checkers to aggressively clean up/reduce the checker state and produce |
||
384 | /// precise diagnostics. |
||
385 | void runCheckersForDeadSymbols(ExplodedNodeSet &Dst, |
||
386 | const ExplodedNodeSet &Src, |
||
387 | SymbolReaper &SymReaper, const Stmt *S, |
||
388 | ExprEngine &Eng, |
||
389 | ProgramPoint::Kind K); |
||
390 | |||
391 | /// Run checkers for region changes. |
||
392 | /// |
||
393 | /// This corresponds to the check::RegionChanges callback. |
||
394 | /// \param state The current program state. |
||
395 | /// \param invalidated A set of all symbols potentially touched by the change. |
||
396 | /// \param ExplicitRegions The regions explicitly requested for invalidation. |
||
397 | /// For example, in the case of a function call, these would be arguments. |
||
398 | /// \param Regions The transitive closure of accessible regions, |
||
399 | /// i.e. all regions that may have been touched by this change. |
||
400 | /// \param Call The call expression wrapper if the regions are invalidated |
||
401 | /// by a call. |
||
402 | ProgramStateRef |
||
403 | runCheckersForRegionChanges(ProgramStateRef state, |
||
404 | const InvalidatedSymbols *invalidated, |
||
405 | ArrayRef<const MemRegion *> ExplicitRegions, |
||
406 | ArrayRef<const MemRegion *> Regions, |
||
407 | const LocationContext *LCtx, |
||
408 | const CallEvent *Call); |
||
409 | |||
410 | /// Run checkers when pointers escape. |
||
411 | /// |
||
412 | /// This notifies the checkers about pointer escape, which occurs whenever |
||
413 | /// the analyzer cannot track the symbol any more. For example, as a |
||
414 | /// result of assigning a pointer into a global or when it's passed to a |
||
415 | /// function call the analyzer cannot model. |
||
416 | /// |
||
417 | /// \param State The state at the point of escape. |
||
418 | /// \param Escaped The list of escaped symbols. |
||
419 | /// \param Call The corresponding CallEvent, if the symbols escape as |
||
420 | /// parameters to the given call. |
||
421 | /// \param Kind The reason of pointer escape. |
||
422 | /// \param ITraits Information about invalidation for a particular |
||
423 | /// region/symbol. |
||
424 | /// \returns Checkers can modify the state by returning a new one. |
||
425 | ProgramStateRef |
||
426 | runCheckersForPointerEscape(ProgramStateRef State, |
||
427 | const InvalidatedSymbols &Escaped, |
||
428 | const CallEvent *Call, |
||
429 | PointerEscapeKind Kind, |
||
430 | RegionAndSymbolInvalidationTraits *ITraits); |
||
431 | |||
432 | /// Run checkers for handling assumptions on symbolic values. |
||
433 | ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state, |
||
434 | SVal Cond, bool Assumption); |
||
435 | |||
436 | /// Run checkers for evaluating a call. |
||
437 | /// |
||
438 | /// Warning: Currently, the CallEvent MUST come from a CallExpr! |
||
439 | void runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, |
||
440 | const CallEvent &CE, ExprEngine &Eng, |
||
441 | const EvalCallOptions &CallOpts); |
||
442 | |||
443 | /// Run checkers for the entire Translation Unit. |
||
444 | void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU, |
||
445 | AnalysisManager &mgr, |
||
446 | BugReporter &BR); |
||
447 | |||
448 | /// Run checkers for debug-printing a ProgramState. |
||
449 | /// |
||
450 | /// Unlike most other callbacks, any checker can simply implement the virtual |
||
451 | /// method CheckerBase::printState if it has custom data to print. |
||
452 | /// |
||
453 | /// \param Out The output stream |
||
454 | /// \param State The state being printed |
||
455 | /// \param NL The preferred representation of a newline. |
||
456 | /// \param Space The preferred space between the left side and the message. |
||
457 | /// \param IsDot Whether the message will be printed in 'dot' format. |
||
458 | void runCheckersForPrintStateJson(raw_ostream &Out, ProgramStateRef State, |
||
459 | const char *NL = "\n", |
||
460 | unsigned int Space = 0, |
||
461 | bool IsDot = false) const; |
||
462 | |||
463 | //===----------------------------------------------------------------------===// |
||
464 | // Internal registration functions for AST traversing. |
||
465 | //===----------------------------------------------------------------------===// |
||
466 | |||
467 | // Functions used by the registration mechanism, checkers should not touch |
||
468 | // these directly. |
||
469 | |||
470 | using CheckDeclFunc = |
||
471 | CheckerFn<void (const Decl *, AnalysisManager&, BugReporter &)>; |
||
472 | |||
473 | using HandlesDeclFunc = bool (*)(const Decl *D); |
||
474 | |||
475 | void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn); |
||
476 | |||
477 | void _registerForBody(CheckDeclFunc checkfn); |
||
478 | |||
479 | //===----------------------------------------------------------------------===// |
||
480 | // Internal registration functions for path-sensitive checking. |
||
481 | //===----------------------------------------------------------------------===// |
||
482 | |||
483 | using CheckStmtFunc = CheckerFn<void (const Stmt *, CheckerContext &)>; |
||
484 | |||
485 | using CheckObjCMessageFunc = |
||
486 | CheckerFn<void (const ObjCMethodCall &, CheckerContext &)>; |
||
487 | |||
488 | using CheckCallFunc = |
||
489 | CheckerFn<void (const CallEvent &, CheckerContext &)>; |
||
490 | |||
491 | using CheckLocationFunc = |
||
492 | CheckerFn<void (const SVal &location, bool isLoad, const Stmt *S, |
||
493 | CheckerContext &)>; |
||
494 | |||
495 | using CheckBindFunc = |
||
496 | CheckerFn<void (const SVal &location, const SVal &val, const Stmt *S, |
||
497 | CheckerContext &)>; |
||
498 | |||
499 | using CheckEndAnalysisFunc = |
||
500 | CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>; |
||
501 | |||
502 | using CheckBeginFunctionFunc = CheckerFn<void (CheckerContext &)>; |
||
503 | |||
504 | using CheckEndFunctionFunc = |
||
505 | CheckerFn<void (const ReturnStmt *, CheckerContext &)>; |
||
506 | |||
507 | using CheckBranchConditionFunc = |
||
508 | CheckerFn<void (const Stmt *, CheckerContext &)>; |
||
509 | |||
510 | using CheckNewAllocatorFunc = |
||
511 | CheckerFn<void(const CXXAllocatorCall &Call, CheckerContext &)>; |
||
512 | |||
513 | using CheckDeadSymbolsFunc = |
||
514 | CheckerFn<void (SymbolReaper &, CheckerContext &)>; |
||
515 | |||
516 | using CheckLiveSymbolsFunc = CheckerFn<void (ProgramStateRef,SymbolReaper &)>; |
||
517 | |||
518 | using CheckRegionChangesFunc = |
||
519 | CheckerFn<ProgramStateRef (ProgramStateRef, |
||
520 | const InvalidatedSymbols *symbols, |
||
521 | ArrayRef<const MemRegion *> ExplicitRegions, |
||
522 | ArrayRef<const MemRegion *> Regions, |
||
523 | const LocationContext *LCtx, |
||
524 | const CallEvent *Call)>; |
||
525 | |||
526 | using CheckPointerEscapeFunc = |
||
527 | CheckerFn<ProgramStateRef (ProgramStateRef, |
||
528 | const InvalidatedSymbols &Escaped, |
||
529 | const CallEvent *Call, PointerEscapeKind Kind, |
||
530 | RegionAndSymbolInvalidationTraits *ITraits)>; |
||
531 | |||
532 | using EvalAssumeFunc = |
||
533 | CheckerFn<ProgramStateRef (ProgramStateRef, const SVal &cond, |
||
534 | bool assumption)>; |
||
535 | |||
536 | using EvalCallFunc = CheckerFn<bool (const CallEvent &, CheckerContext &)>; |
||
537 | |||
538 | using CheckEndOfTranslationUnit = |
||
539 | CheckerFn<void (const TranslationUnitDecl *, AnalysisManager &, |
||
540 | BugReporter &)>; |
||
541 | |||
542 | using HandlesStmtFunc = bool (*)(const Stmt *D); |
||
543 | |||
544 | void _registerForPreStmt(CheckStmtFunc checkfn, |
||
545 | HandlesStmtFunc isForStmtFn); |
||
546 | void _registerForPostStmt(CheckStmtFunc checkfn, |
||
547 | HandlesStmtFunc isForStmtFn); |
||
548 | |||
549 | void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn); |
||
550 | void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn); |
||
551 | |||
552 | void _registerForObjCMessageNil(CheckObjCMessageFunc checkfn); |
||
553 | |||
554 | void _registerForPreCall(CheckCallFunc checkfn); |
||
555 | void _registerForPostCall(CheckCallFunc checkfn); |
||
556 | |||
557 | void _registerForLocation(CheckLocationFunc checkfn); |
||
558 | |||
559 | void _registerForBind(CheckBindFunc checkfn); |
||
560 | |||
561 | void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn); |
||
562 | |||
563 | void _registerForBeginFunction(CheckBeginFunctionFunc checkfn); |
||
564 | void _registerForEndFunction(CheckEndFunctionFunc checkfn); |
||
565 | |||
566 | void _registerForBranchCondition(CheckBranchConditionFunc checkfn); |
||
567 | |||
568 | void _registerForNewAllocator(CheckNewAllocatorFunc checkfn); |
||
569 | |||
570 | void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn); |
||
571 | |||
572 | void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn); |
||
573 | |||
574 | void _registerForRegionChanges(CheckRegionChangesFunc checkfn); |
||
575 | |||
576 | void _registerForPointerEscape(CheckPointerEscapeFunc checkfn); |
||
577 | |||
578 | void _registerForConstPointerEscape(CheckPointerEscapeFunc checkfn); |
||
579 | |||
580 | void _registerForEvalAssume(EvalAssumeFunc checkfn); |
||
581 | |||
582 | void _registerForEvalCall(EvalCallFunc checkfn); |
||
583 | |||
584 | void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn); |
||
585 | |||
586 | //===----------------------------------------------------------------------===// |
||
587 | // Internal registration functions for events. |
||
588 | //===----------------------------------------------------------------------===// |
||
589 | |||
590 | using EventTag = void *; |
||
591 | using CheckEventFunc = CheckerFn<void (const void *event)>; |
||
592 | |||
593 | template <typename EVENT> |
||
594 | void _registerListenerForEvent(CheckEventFunc checkfn) { |
||
595 | EventInfo &info = Events[&EVENT::Tag]; |
||
596 | info.Checkers.push_back(checkfn); |
||
597 | } |
||
598 | |||
599 | template <typename EVENT> |
||
600 | void _registerDispatcherForEvent() { |
||
601 | EventInfo &info = Events[&EVENT::Tag]; |
||
602 | info.HasDispatcher = true; |
||
603 | } |
||
604 | |||
605 | template <typename EVENT> |
||
606 | void _dispatchEvent(const EVENT &event) const { |
||
607 | EventsTy::const_iterator I = Events.find(&EVENT::Tag); |
||
608 | if (I == Events.end()) |
||
609 | return; |
||
610 | const EventInfo &info = I->second; |
||
611 | for (const auto &Checker : info.Checkers) |
||
612 | Checker(&event); |
||
613 | } |
||
614 | |||
615 | //===----------------------------------------------------------------------===// |
||
616 | // Implementation details. |
||
617 | //===----------------------------------------------------------------------===// |
||
618 | |||
619 | private: |
||
620 | template <typename CHECKER> |
||
621 | static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); } |
||
622 | |||
623 | template <typename T> |
||
624 | static void *getTag() { static int tag; return &tag; } |
||
625 | |||
626 | llvm::DenseMap<CheckerTag, CheckerRef> CheckerTags; |
||
627 | |||
628 | std::vector<CheckerDtor> CheckerDtors; |
||
629 | |||
630 | struct DeclCheckerInfo { |
||
631 | CheckDeclFunc CheckFn; |
||
632 | HandlesDeclFunc IsForDeclFn; |
||
633 | }; |
||
634 | std::vector<DeclCheckerInfo> DeclCheckers; |
||
635 | |||
636 | std::vector<CheckDeclFunc> BodyCheckers; |
||
637 | |||
638 | using CachedDeclCheckers = SmallVector<CheckDeclFunc, 4>; |
||
639 | using CachedDeclCheckersMapTy = llvm::DenseMap<unsigned, CachedDeclCheckers>; |
||
640 | CachedDeclCheckersMapTy CachedDeclCheckersMap; |
||
641 | |||
642 | struct StmtCheckerInfo { |
||
643 | CheckStmtFunc CheckFn; |
||
644 | HandlesStmtFunc IsForStmtFn; |
||
645 | bool IsPreVisit; |
||
646 | }; |
||
647 | std::vector<StmtCheckerInfo> StmtCheckers; |
||
648 | |||
649 | using CachedStmtCheckers = SmallVector<CheckStmtFunc, 4>; |
||
650 | using CachedStmtCheckersMapTy = llvm::DenseMap<unsigned, CachedStmtCheckers>; |
||
651 | CachedStmtCheckersMapTy CachedStmtCheckersMap; |
||
652 | |||
653 | const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S, |
||
654 | bool isPreVisit); |
||
655 | |||
656 | /// Returns the checkers that have registered for callbacks of the |
||
657 | /// given \p Kind. |
||
658 | const std::vector<CheckObjCMessageFunc> & |
||
659 | getObjCMessageCheckers(ObjCMessageVisitKind Kind) const; |
||
660 | |||
661 | std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers; |
||
662 | std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers; |
||
663 | std::vector<CheckObjCMessageFunc> ObjCMessageNilCheckers; |
||
664 | |||
665 | std::vector<CheckCallFunc> PreCallCheckers; |
||
666 | std::vector<CheckCallFunc> PostCallCheckers; |
||
667 | |||
668 | std::vector<CheckLocationFunc> LocationCheckers; |
||
669 | |||
670 | std::vector<CheckBindFunc> BindCheckers; |
||
671 | |||
672 | std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers; |
||
673 | |||
674 | std::vector<CheckBeginFunctionFunc> BeginFunctionCheckers; |
||
675 | std::vector<CheckEndFunctionFunc> EndFunctionCheckers; |
||
676 | |||
677 | std::vector<CheckBranchConditionFunc> BranchConditionCheckers; |
||
678 | |||
679 | std::vector<CheckNewAllocatorFunc> NewAllocatorCheckers; |
||
680 | |||
681 | std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers; |
||
682 | |||
683 | std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers; |
||
684 | |||
685 | std::vector<CheckRegionChangesFunc> RegionChangesCheckers; |
||
686 | |||
687 | std::vector<CheckPointerEscapeFunc> PointerEscapeCheckers; |
||
688 | |||
689 | std::vector<EvalAssumeFunc> EvalAssumeCheckers; |
||
690 | |||
691 | std::vector<EvalCallFunc> EvalCallCheckers; |
||
692 | |||
693 | std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers; |
||
694 | |||
695 | struct EventInfo { |
||
696 | SmallVector<CheckEventFunc, 4> Checkers; |
||
697 | bool HasDispatcher = false; |
||
698 | |||
699 | EventInfo() = default; |
||
700 | }; |
||
701 | |||
702 | using EventsTy = llvm::DenseMap<EventTag, EventInfo>; |
||
703 | EventsTy Events; |
||
704 | }; |
||
705 | |||
706 | } // namespace ento |
||
707 | |||
708 | } // namespace clang |
||
709 | |||
710 | #endif // LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H |