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 | class 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(x: 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=*/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=*/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(visitKind: 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(visitKind: 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(visitKind: 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=*/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=*/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 = CheckerFn<void(SVal location, bool isLoad, |
492 | const Stmt *S, CheckerContext &)>; |
493 | |
494 | using CheckBindFunc = |
495 | CheckerFn<void(SVal location, SVal val, const Stmt *S, CheckerContext &)>; |
496 | |
497 | using CheckEndAnalysisFunc = |
498 | CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>; |
499 | |
500 | using CheckBeginFunctionFunc = CheckerFn<void (CheckerContext &)>; |
501 | |
502 | using CheckEndFunctionFunc = |
503 | CheckerFn<void (const ReturnStmt *, CheckerContext &)>; |
504 | |
505 | using CheckBranchConditionFunc = |
506 | CheckerFn<void (const Stmt *, CheckerContext &)>; |
507 | |
508 | using CheckNewAllocatorFunc = |
509 | CheckerFn<void(const CXXAllocatorCall &Call, CheckerContext &)>; |
510 | |
511 | using CheckDeadSymbolsFunc = |
512 | CheckerFn<void (SymbolReaper &, CheckerContext &)>; |
513 | |
514 | using CheckLiveSymbolsFunc = CheckerFn<void (ProgramStateRef,SymbolReaper &)>; |
515 | |
516 | using CheckRegionChangesFunc = |
517 | CheckerFn<ProgramStateRef (ProgramStateRef, |
518 | const InvalidatedSymbols *symbols, |
519 | ArrayRef<const MemRegion *> ExplicitRegions, |
520 | ArrayRef<const MemRegion *> Regions, |
521 | const LocationContext *LCtx, |
522 | const CallEvent *Call)>; |
523 | |
524 | using CheckPointerEscapeFunc = |
525 | CheckerFn<ProgramStateRef (ProgramStateRef, |
526 | const InvalidatedSymbols &Escaped, |
527 | const CallEvent *Call, PointerEscapeKind Kind, |
528 | RegionAndSymbolInvalidationTraits *ITraits)>; |
529 | |
530 | using EvalAssumeFunc = |
531 | CheckerFn<ProgramStateRef(ProgramStateRef, SVal cond, bool assumption)>; |
532 | |
533 | using EvalCallFunc = CheckerFn<bool (const CallEvent &, CheckerContext &)>; |
534 | |
535 | using CheckEndOfTranslationUnit = |
536 | CheckerFn<void (const TranslationUnitDecl *, AnalysisManager &, |
537 | BugReporter &)>; |
538 | |
539 | using HandlesStmtFunc = bool (*)(const Stmt *D); |
540 | |
541 | void _registerForPreStmt(CheckStmtFunc checkfn, |
542 | HandlesStmtFunc isForStmtFn); |
543 | void _registerForPostStmt(CheckStmtFunc checkfn, |
544 | HandlesStmtFunc isForStmtFn); |
545 | |
546 | void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn); |
547 | void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn); |
548 | |
549 | void _registerForObjCMessageNil(CheckObjCMessageFunc checkfn); |
550 | |
551 | void _registerForPreCall(CheckCallFunc checkfn); |
552 | void _registerForPostCall(CheckCallFunc checkfn); |
553 | |
554 | void _registerForLocation(CheckLocationFunc checkfn); |
555 | |
556 | void _registerForBind(CheckBindFunc checkfn); |
557 | |
558 | void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn); |
559 | |
560 | void _registerForBeginFunction(CheckBeginFunctionFunc checkfn); |
561 | void _registerForEndFunction(CheckEndFunctionFunc checkfn); |
562 | |
563 | void _registerForBranchCondition(CheckBranchConditionFunc checkfn); |
564 | |
565 | void _registerForNewAllocator(CheckNewAllocatorFunc checkfn); |
566 | |
567 | void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn); |
568 | |
569 | void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn); |
570 | |
571 | void _registerForRegionChanges(CheckRegionChangesFunc checkfn); |
572 | |
573 | void _registerForPointerEscape(CheckPointerEscapeFunc checkfn); |
574 | |
575 | void _registerForConstPointerEscape(CheckPointerEscapeFunc checkfn); |
576 | |
577 | void _registerForEvalAssume(EvalAssumeFunc checkfn); |
578 | |
579 | void _registerForEvalCall(EvalCallFunc checkfn); |
580 | |
581 | void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn); |
582 | |
583 | //===----------------------------------------------------------------------===// |
584 | // Internal registration functions for events. |
585 | //===----------------------------------------------------------------------===// |
586 | |
587 | using EventTag = void *; |
588 | using CheckEventFunc = CheckerFn<void (const void *event)>; |
589 | |
590 | template <typename EVENT> |
591 | void _registerListenerForEvent(CheckEventFunc checkfn) { |
592 | EventInfo &info = Events[&EVENT::Tag]; |
593 | info.Checkers.push_back(Elt: checkfn); |
594 | } |
595 | |
596 | template <typename EVENT> |
597 | void _registerDispatcherForEvent() { |
598 | EventInfo &info = Events[&EVENT::Tag]; |
599 | info.HasDispatcher = true; |
600 | } |
601 | |
602 | template <typename EVENT> |
603 | void _dispatchEvent(const EVENT &event) const { |
604 | EventsTy::const_iterator I = Events.find(&EVENT::Tag); |
605 | if (I == Events.end()) |
606 | return; |
607 | const EventInfo &info = I->second; |
608 | for (const auto &Checker : info.Checkers) |
609 | Checker(&event); |
610 | } |
611 | |
612 | //===----------------------------------------------------------------------===// |
613 | // Implementation details. |
614 | //===----------------------------------------------------------------------===// |
615 | |
616 | private: |
617 | template <typename CHECKER> |
618 | static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); } |
619 | |
620 | template <typename T> |
621 | static void *getTag() { static int tag; return &tag; } |
622 | |
623 | llvm::DenseMap<CheckerTag, CheckerRef> CheckerTags; |
624 | |
625 | std::vector<CheckerDtor> CheckerDtors; |
626 | |
627 | struct DeclCheckerInfo { |
628 | CheckDeclFunc CheckFn; |
629 | HandlesDeclFunc IsForDeclFn; |
630 | }; |
631 | std::vector<DeclCheckerInfo> DeclCheckers; |
632 | |
633 | std::vector<CheckDeclFunc> BodyCheckers; |
634 | |
635 | using CachedDeclCheckers = SmallVector<CheckDeclFunc, 4>; |
636 | using CachedDeclCheckersMapTy = llvm::DenseMap<unsigned, CachedDeclCheckers>; |
637 | CachedDeclCheckersMapTy CachedDeclCheckersMap; |
638 | |
639 | struct StmtCheckerInfo { |
640 | CheckStmtFunc CheckFn; |
641 | HandlesStmtFunc IsForStmtFn; |
642 | bool IsPreVisit; |
643 | }; |
644 | std::vector<StmtCheckerInfo> StmtCheckers; |
645 | |
646 | using CachedStmtCheckers = SmallVector<CheckStmtFunc, 4>; |
647 | using CachedStmtCheckersMapTy = llvm::DenseMap<unsigned, CachedStmtCheckers>; |
648 | CachedStmtCheckersMapTy CachedStmtCheckersMap; |
649 | |
650 | const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S, |
651 | bool isPreVisit); |
652 | |
653 | /// Returns the checkers that have registered for callbacks of the |
654 | /// given \p Kind. |
655 | const std::vector<CheckObjCMessageFunc> & |
656 | getObjCMessageCheckers(ObjCMessageVisitKind Kind) const; |
657 | |
658 | std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers; |
659 | std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers; |
660 | std::vector<CheckObjCMessageFunc> ObjCMessageNilCheckers; |
661 | |
662 | std::vector<CheckCallFunc> PreCallCheckers; |
663 | std::vector<CheckCallFunc> PostCallCheckers; |
664 | |
665 | std::vector<CheckLocationFunc> LocationCheckers; |
666 | |
667 | std::vector<CheckBindFunc> BindCheckers; |
668 | |
669 | std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers; |
670 | |
671 | std::vector<CheckBeginFunctionFunc> BeginFunctionCheckers; |
672 | std::vector<CheckEndFunctionFunc> EndFunctionCheckers; |
673 | |
674 | std::vector<CheckBranchConditionFunc> BranchConditionCheckers; |
675 | |
676 | std::vector<CheckNewAllocatorFunc> NewAllocatorCheckers; |
677 | |
678 | std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers; |
679 | |
680 | std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers; |
681 | |
682 | std::vector<CheckRegionChangesFunc> RegionChangesCheckers; |
683 | |
684 | std::vector<CheckPointerEscapeFunc> PointerEscapeCheckers; |
685 | |
686 | std::vector<EvalAssumeFunc> EvalAssumeCheckers; |
687 | |
688 | std::vector<EvalCallFunc> EvalCallCheckers; |
689 | |
690 | std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers; |
691 | |
692 | struct EventInfo { |
693 | SmallVector<CheckEventFunc, 4> Checkers; |
694 | bool HasDispatcher = false; |
695 | |
696 | EventInfo() = default; |
697 | }; |
698 | |
699 | using EventsTy = llvm::DenseMap<EventTag, EventInfo>; |
700 | EventsTy Events; |
701 | }; |
702 | |
703 | } // namespace ento |
704 | |
705 | } // namespace clang |
706 | |
707 | #endif // LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H |
708 | |