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