File indexing completed on 2026-05-10 08:37:10
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H
0014 #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H
0015
0016 #include "clang/Analysis/ProgramPoint.h"
0017 #include "clang/Basic/Diagnostic.h"
0018 #include "clang/Basic/LangOptions.h"
0019 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
0020 #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
0021 #include "llvm/ADT/ArrayRef.h"
0022 #include "llvm/ADT/DenseMap.h"
0023 #include "llvm/ADT/SmallVector.h"
0024 #include "llvm/ADT/StringRef.h"
0025 #include <vector>
0026
0027 namespace clang {
0028
0029 class AnalyzerOptions;
0030 class CallExpr;
0031 class Decl;
0032 class LocationContext;
0033 class Stmt;
0034 class TranslationUnitDecl;
0035
0036 namespace ento {
0037
0038 class AnalysisManager;
0039 class CXXAllocatorCall;
0040 class BugReporter;
0041 class CallEvent;
0042 class CheckerBase;
0043 class CheckerContext;
0044 class CheckerRegistry;
0045 struct CheckerRegistryData;
0046 class ExplodedGraph;
0047 class ExplodedNode;
0048 class ExplodedNodeSet;
0049 class ExprEngine;
0050 struct EvalCallOptions;
0051 class MemRegion;
0052 class NodeBuilderContext;
0053 class ObjCMethodCall;
0054 class RegionAndSymbolInvalidationTraits;
0055 class SVal;
0056 class SymbolReaper;
0057
0058 template <typename T> class CheckerFn;
0059
0060 template <typename RET, typename... Ps>
0061 class CheckerFn<RET(Ps...)> {
0062 using Func = RET (*)(void *, Ps...);
0063
0064 Func Fn;
0065
0066 public:
0067 CheckerBase *Checker;
0068
0069 CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) {}
0070
0071 RET operator()(Ps... ps) const {
0072 return Fn(Checker, ps...);
0073 }
0074 };
0075
0076
0077
0078 enum PointerEscapeKind {
0079
0080
0081 PSK_EscapeOnBind,
0082
0083
0084 PSK_DirectEscapeOnCall,
0085
0086
0087
0088
0089 PSK_IndirectEscapeOnCall,
0090
0091
0092
0093
0094 PSK_EscapeOutParameters,
0095
0096
0097
0098 PSK_EscapeOther
0099 };
0100
0101
0102
0103
0104
0105
0106 class CheckerNameRef {
0107 friend class ::clang::ento::CheckerRegistry;
0108
0109 StringRef Name;
0110
0111 explicit CheckerNameRef(StringRef Name) : Name(Name) {}
0112
0113 public:
0114 CheckerNameRef() = default;
0115
0116 StringRef getName() const { return Name; }
0117 operator StringRef() const { return Name; }
0118 };
0119
0120 enum class ObjCMessageVisitKind {
0121 Pre,
0122 Post,
0123 MessageNil
0124 };
0125
0126 class CheckerManager {
0127 ASTContext *Context = nullptr;
0128 const LangOptions LangOpts;
0129 const AnalyzerOptions &AOptions;
0130 const Preprocessor *PP = nullptr;
0131 CheckerNameRef CurrentCheckerName;
0132 DiagnosticsEngine &Diags;
0133 std::unique_ptr<CheckerRegistryData> RegistryData;
0134
0135 public:
0136
0137
0138
0139
0140
0141
0142 CheckerManager(
0143 ASTContext &Context, AnalyzerOptions &AOptions, const Preprocessor &PP,
0144 ArrayRef<std::string> plugins,
0145 ArrayRef<std::function<void(CheckerRegistry &)>> checkerRegistrationFns);
0146
0147
0148
0149
0150 CheckerManager(ASTContext &Context, AnalyzerOptions &AOptions,
0151 const Preprocessor &PP)
0152 : CheckerManager(Context, AOptions, PP, {}, {}) {}
0153
0154
0155
0156
0157 CheckerManager(AnalyzerOptions &AOptions, const LangOptions &LangOpts,
0158 DiagnosticsEngine &Diags, ArrayRef<std::string> plugins);
0159
0160 ~CheckerManager();
0161
0162 void setCurrentCheckerName(CheckerNameRef name) { CurrentCheckerName = name; }
0163 CheckerNameRef getCurrentCheckerName() const { return CurrentCheckerName; }
0164
0165 bool hasPathSensitiveCheckers() const;
0166
0167 const LangOptions &getLangOpts() const { return LangOpts; }
0168 const AnalyzerOptions &getAnalyzerOptions() const { return AOptions; }
0169 const Preprocessor &getPreprocessor() const {
0170 assert(PP);
0171 return *PP;
0172 }
0173 const CheckerRegistryData &getCheckerRegistryData() const {
0174 return *RegistryData;
0175 }
0176 DiagnosticsEngine &getDiagnostics() const { return Diags; }
0177 ASTContext &getASTContext() const {
0178 assert(Context);
0179 return *Context;
0180 }
0181
0182
0183
0184 void reportInvalidCheckerOptionValue(const CheckerBase *C,
0185 StringRef OptionName,
0186 StringRef ExpectedValueDesc) const;
0187
0188 using CheckerRef = CheckerBase *;
0189 using CheckerTag = const void *;
0190 using CheckerDtor = CheckerFn<void ()>;
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201 template <typename CHECKER, typename... AT>
0202 CHECKER *registerChecker(AT &&... Args) {
0203 CheckerTag tag = getTag<CHECKER>();
0204 CheckerRef &ref = CheckerTags[tag];
0205 assert(!ref && "Checker already registered, use getChecker!");
0206
0207 CHECKER *checker = new CHECKER(std::forward<AT>(Args)...);
0208 checker->Name = CurrentCheckerName;
0209 CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>));
0210 CHECKER::_register(checker, *this);
0211 ref = checker;
0212 return checker;
0213 }
0214
0215 template <typename CHECKER>
0216 CHECKER *getChecker() {
0217 CheckerTag tag = getTag<CHECKER>();
0218 assert(CheckerTags.count(tag) != 0 &&
0219 "Requested checker is not registered! Maybe you should add it as a "
0220 "dependency in Checkers.td?");
0221 return static_cast<CHECKER *>(CheckerTags[tag]);
0222 }
0223
0224 template <typename CHECKER> bool isRegisteredChecker() {
0225 return CheckerTags.contains(getTag<CHECKER>());
0226 }
0227
0228
0229
0230
0231
0232
0233 void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
0234 BugReporter &BR);
0235
0236
0237 void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
0238 BugReporter &BR);
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 void runCheckersForPreStmt(ExplodedNodeSet &Dst,
0251 const ExplodedNodeSet &Src,
0252 const Stmt *S,
0253 ExprEngine &Eng) {
0254 runCheckersForStmt(true, Dst, Src, S, Eng);
0255 }
0256
0257
0258
0259
0260
0261
0262
0263 void runCheckersForPostStmt(ExplodedNodeSet &Dst,
0264 const ExplodedNodeSet &Src,
0265 const Stmt *S,
0266 ExprEngine &Eng,
0267 bool wasInlined = false) {
0268 runCheckersForStmt(false, Dst, Src, S, Eng, wasInlined);
0269 }
0270
0271
0272 void runCheckersForStmt(bool isPreVisit,
0273 ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
0274 const Stmt *S, ExprEngine &Eng,
0275 bool wasInlined = false);
0276
0277
0278 void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst,
0279 const ExplodedNodeSet &Src,
0280 const ObjCMethodCall &msg,
0281 ExprEngine &Eng) {
0282 runCheckersForObjCMessage(ObjCMessageVisitKind::Pre, Dst, Src, msg, Eng);
0283 }
0284
0285
0286 void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst,
0287 const ExplodedNodeSet &Src,
0288 const ObjCMethodCall &msg,
0289 ExprEngine &Eng,
0290 bool wasInlined = false) {
0291 runCheckersForObjCMessage(ObjCMessageVisitKind::Post, Dst, Src, msg, Eng,
0292 wasInlined);
0293 }
0294
0295
0296 void runCheckersForObjCMessageNil(ExplodedNodeSet &Dst,
0297 const ExplodedNodeSet &Src,
0298 const ObjCMethodCall &msg,
0299 ExprEngine &Eng) {
0300 runCheckersForObjCMessage(ObjCMessageVisitKind::MessageNil, Dst, Src, msg,
0301 Eng);
0302 }
0303
0304
0305 void runCheckersForObjCMessage(ObjCMessageVisitKind visitKind,
0306 ExplodedNodeSet &Dst,
0307 const ExplodedNodeSet &Src,
0308 const ObjCMethodCall &msg, ExprEngine &Eng,
0309 bool wasInlined = false);
0310
0311
0312 void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
0313 const CallEvent &Call, ExprEngine &Eng) {
0314 runCheckersForCallEvent(true, Dst, Src, Call, Eng);
0315 }
0316
0317
0318 void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
0319 const CallEvent &Call, ExprEngine &Eng,
0320 bool wasInlined = false) {
0321 runCheckersForCallEvent(false, Dst, Src, Call, Eng,
0322 wasInlined);
0323 }
0324
0325
0326 void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst,
0327 const ExplodedNodeSet &Src,
0328 const CallEvent &Call, ExprEngine &Eng,
0329 bool wasInlined = false);
0330
0331
0332 void runCheckersForLocation(ExplodedNodeSet &Dst,
0333 const ExplodedNodeSet &Src,
0334 SVal location,
0335 bool isLoad,
0336 const Stmt *NodeEx,
0337 const Stmt *BoundEx,
0338 ExprEngine &Eng);
0339
0340
0341 void runCheckersForBind(ExplodedNodeSet &Dst,
0342 const ExplodedNodeSet &Src,
0343 SVal location, SVal val,
0344 const Stmt *S, ExprEngine &Eng,
0345 const ProgramPoint &PP);
0346
0347
0348 void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
0349 ExprEngine &Eng);
0350
0351
0352 void runCheckersForBeginFunction(ExplodedNodeSet &Dst,
0353 const BlockEdge &L,
0354 ExplodedNode *Pred,
0355 ExprEngine &Eng);
0356
0357
0358 void runCheckersForEndFunction(NodeBuilderContext &BC,
0359 ExplodedNodeSet &Dst,
0360 ExplodedNode *Pred,
0361 ExprEngine &Eng,
0362 const ReturnStmt *RS);
0363
0364
0365 void runCheckersForBranchCondition(const Stmt *condition,
0366 ExplodedNodeSet &Dst, ExplodedNode *Pred,
0367 ExprEngine &Eng);
0368
0369
0370 void runCheckersForNewAllocator(const CXXAllocatorCall &Call,
0371 ExplodedNodeSet &Dst, ExplodedNode *Pred,
0372 ExprEngine &Eng, bool wasInlined = false);
0373
0374
0375
0376
0377
0378
0379 void runCheckersForLiveSymbols(ProgramStateRef state,
0380 SymbolReaper &SymReaper);
0381
0382
0383
0384
0385
0386
0387 void runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
0388 const ExplodedNodeSet &Src,
0389 SymbolReaper &SymReaper, const Stmt *S,
0390 ExprEngine &Eng,
0391 ProgramPoint::Kind K);
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404 ProgramStateRef
0405 runCheckersForRegionChanges(ProgramStateRef state,
0406 const InvalidatedSymbols *invalidated,
0407 ArrayRef<const MemRegion *> ExplicitRegions,
0408 ArrayRef<const MemRegion *> Regions,
0409 const LocationContext *LCtx,
0410 const CallEvent *Call);
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427 ProgramStateRef
0428 runCheckersForPointerEscape(ProgramStateRef State,
0429 const InvalidatedSymbols &Escaped,
0430 const CallEvent *Call,
0431 PointerEscapeKind Kind,
0432 RegionAndSymbolInvalidationTraits *ITraits);
0433
0434
0435 ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
0436 SVal Cond, bool Assumption);
0437
0438
0439
0440
0441 void runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
0442 const CallEvent &CE, ExprEngine &Eng,
0443 const EvalCallOptions &CallOpts);
0444
0445
0446 void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU,
0447 AnalysisManager &mgr,
0448 BugReporter &BR);
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460 void runCheckersForPrintStateJson(raw_ostream &Out, ProgramStateRef State,
0461 const char *NL = "\n",
0462 unsigned int Space = 0,
0463 bool IsDot = false) const;
0464
0465
0466
0467
0468
0469
0470
0471
0472 using CheckDeclFunc =
0473 CheckerFn<void (const Decl *, AnalysisManager&, BugReporter &)>;
0474
0475 using HandlesDeclFunc = bool (*)(const Decl *D);
0476
0477 void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn);
0478
0479 void _registerForBody(CheckDeclFunc checkfn);
0480
0481
0482
0483
0484
0485 using CheckStmtFunc = CheckerFn<void (const Stmt *, CheckerContext &)>;
0486
0487 using CheckObjCMessageFunc =
0488 CheckerFn<void (const ObjCMethodCall &, CheckerContext &)>;
0489
0490 using CheckCallFunc =
0491 CheckerFn<void (const CallEvent &, CheckerContext &)>;
0492
0493 using CheckLocationFunc = CheckerFn<void(SVal location, bool isLoad,
0494 const Stmt *S, CheckerContext &)>;
0495
0496 using CheckBindFunc =
0497 CheckerFn<void(SVal location, SVal val, const Stmt *S, CheckerContext &)>;
0498
0499 using CheckEndAnalysisFunc =
0500 CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>;
0501
0502 using CheckBeginFunctionFunc = CheckerFn<void (CheckerContext &)>;
0503
0504 using CheckEndFunctionFunc =
0505 CheckerFn<void (const ReturnStmt *, CheckerContext &)>;
0506
0507 using CheckBranchConditionFunc =
0508 CheckerFn<void (const Stmt *, CheckerContext &)>;
0509
0510 using CheckNewAllocatorFunc =
0511 CheckerFn<void(const CXXAllocatorCall &Call, CheckerContext &)>;
0512
0513 using CheckDeadSymbolsFunc =
0514 CheckerFn<void (SymbolReaper &, CheckerContext &)>;
0515
0516 using CheckLiveSymbolsFunc = CheckerFn<void (ProgramStateRef,SymbolReaper &)>;
0517
0518 using CheckRegionChangesFunc =
0519 CheckerFn<ProgramStateRef (ProgramStateRef,
0520 const InvalidatedSymbols *symbols,
0521 ArrayRef<const MemRegion *> ExplicitRegions,
0522 ArrayRef<const MemRegion *> Regions,
0523 const LocationContext *LCtx,
0524 const CallEvent *Call)>;
0525
0526 using CheckPointerEscapeFunc =
0527 CheckerFn<ProgramStateRef (ProgramStateRef,
0528 const InvalidatedSymbols &Escaped,
0529 const CallEvent *Call, PointerEscapeKind Kind,
0530 RegionAndSymbolInvalidationTraits *ITraits)>;
0531
0532 using EvalAssumeFunc =
0533 CheckerFn<ProgramStateRef(ProgramStateRef, SVal cond, bool assumption)>;
0534
0535 using EvalCallFunc = CheckerFn<bool (const CallEvent &, CheckerContext &)>;
0536
0537 using CheckEndOfTranslationUnit =
0538 CheckerFn<void (const TranslationUnitDecl *, AnalysisManager &,
0539 BugReporter &)>;
0540
0541 using HandlesStmtFunc = bool (*)(const Stmt *D);
0542
0543 void _registerForPreStmt(CheckStmtFunc checkfn,
0544 HandlesStmtFunc isForStmtFn);
0545 void _registerForPostStmt(CheckStmtFunc checkfn,
0546 HandlesStmtFunc isForStmtFn);
0547
0548 void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn);
0549 void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn);
0550
0551 void _registerForObjCMessageNil(CheckObjCMessageFunc checkfn);
0552
0553 void _registerForPreCall(CheckCallFunc checkfn);
0554 void _registerForPostCall(CheckCallFunc checkfn);
0555
0556 void _registerForLocation(CheckLocationFunc checkfn);
0557
0558 void _registerForBind(CheckBindFunc checkfn);
0559
0560 void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn);
0561
0562 void _registerForBeginFunction(CheckBeginFunctionFunc checkfn);
0563 void _registerForEndFunction(CheckEndFunctionFunc checkfn);
0564
0565 void _registerForBranchCondition(CheckBranchConditionFunc checkfn);
0566
0567 void _registerForNewAllocator(CheckNewAllocatorFunc checkfn);
0568
0569 void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn);
0570
0571 void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn);
0572
0573 void _registerForRegionChanges(CheckRegionChangesFunc checkfn);
0574
0575 void _registerForPointerEscape(CheckPointerEscapeFunc checkfn);
0576
0577 void _registerForConstPointerEscape(CheckPointerEscapeFunc checkfn);
0578
0579 void _registerForEvalAssume(EvalAssumeFunc checkfn);
0580
0581 void _registerForEvalCall(EvalCallFunc checkfn);
0582
0583 void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn);
0584
0585
0586
0587
0588
0589 using EventTag = void *;
0590 using CheckEventFunc = CheckerFn<void (const void *event)>;
0591
0592 template <typename EVENT>
0593 void _registerListenerForEvent(CheckEventFunc checkfn) {
0594 EventInfo &info = Events[&EVENT::Tag];
0595 info.Checkers.push_back(checkfn);
0596 }
0597
0598 template <typename EVENT>
0599 void _registerDispatcherForEvent() {
0600 EventInfo &info = Events[&EVENT::Tag];
0601 info.HasDispatcher = true;
0602 }
0603
0604 template <typename EVENT>
0605 void _dispatchEvent(const EVENT &event) const {
0606 EventsTy::const_iterator I = Events.find(&EVENT::Tag);
0607 if (I == Events.end())
0608 return;
0609 const EventInfo &info = I->second;
0610 for (const auto &Checker : info.Checkers)
0611 Checker(&event);
0612 }
0613
0614
0615
0616
0617
0618 private:
0619 template <typename CHECKER>
0620 static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); }
0621
0622 template <typename T>
0623 static void *getTag() { static int tag; return &tag; }
0624
0625 llvm::DenseMap<CheckerTag, CheckerRef> CheckerTags;
0626
0627 std::vector<CheckerDtor> CheckerDtors;
0628
0629 struct DeclCheckerInfo {
0630 CheckDeclFunc CheckFn;
0631 HandlesDeclFunc IsForDeclFn;
0632 };
0633 std::vector<DeclCheckerInfo> DeclCheckers;
0634
0635 std::vector<CheckDeclFunc> BodyCheckers;
0636
0637 using CachedDeclCheckers = SmallVector<CheckDeclFunc, 4>;
0638 using CachedDeclCheckersMapTy = llvm::DenseMap<unsigned, CachedDeclCheckers>;
0639 CachedDeclCheckersMapTy CachedDeclCheckersMap;
0640
0641 struct StmtCheckerInfo {
0642 CheckStmtFunc CheckFn;
0643 HandlesStmtFunc IsForStmtFn;
0644 bool IsPreVisit;
0645 };
0646 std::vector<StmtCheckerInfo> StmtCheckers;
0647
0648 using CachedStmtCheckers = SmallVector<CheckStmtFunc, 4>;
0649 using CachedStmtCheckersMapTy = llvm::DenseMap<unsigned, CachedStmtCheckers>;
0650 CachedStmtCheckersMapTy CachedStmtCheckersMap;
0651
0652 const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S,
0653 bool isPreVisit);
0654
0655
0656
0657 const std::vector<CheckObjCMessageFunc> &
0658 getObjCMessageCheckers(ObjCMessageVisitKind Kind) const;
0659
0660 std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers;
0661 std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers;
0662 std::vector<CheckObjCMessageFunc> ObjCMessageNilCheckers;
0663
0664 std::vector<CheckCallFunc> PreCallCheckers;
0665 std::vector<CheckCallFunc> PostCallCheckers;
0666
0667 std::vector<CheckLocationFunc> LocationCheckers;
0668
0669 std::vector<CheckBindFunc> BindCheckers;
0670
0671 std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers;
0672
0673 std::vector<CheckBeginFunctionFunc> BeginFunctionCheckers;
0674 std::vector<CheckEndFunctionFunc> EndFunctionCheckers;
0675
0676 std::vector<CheckBranchConditionFunc> BranchConditionCheckers;
0677
0678 std::vector<CheckNewAllocatorFunc> NewAllocatorCheckers;
0679
0680 std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers;
0681
0682 std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers;
0683
0684 std::vector<CheckRegionChangesFunc> RegionChangesCheckers;
0685
0686 std::vector<CheckPointerEscapeFunc> PointerEscapeCheckers;
0687
0688 std::vector<EvalAssumeFunc> EvalAssumeCheckers;
0689
0690 std::vector<EvalCallFunc> EvalCallCheckers;
0691
0692 std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers;
0693
0694 struct EventInfo {
0695 SmallVector<CheckEventFunc, 4> Checkers;
0696 bool HasDispatcher = false;
0697
0698 EventInfo() = default;
0699 };
0700
0701 using EventsTy = llvm::DenseMap<EventTag, EventInfo>;
0702 EventsTy Events;
0703 };
0704
0705 }
0706
0707 }
0708
0709 #endif