File indexing completed on 2026-05-10 08:37:07
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
0015 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
0016
0017 #include "clang/Analysis/ProgramPoint.h"
0018 #include "clang/Basic/LLVM.h"
0019 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
0020 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
0021 #include "llvm/ADT/FoldingSet.h"
0022 #include "llvm/ADT/IntrusiveRefCntPtr.h"
0023 #include "llvm/ADT/STLExtras.h"
0024 #include "llvm/ADT/SmallPtrSet.h"
0025 #include "llvm/ADT/StringRef.h"
0026 #include <list>
0027 #include <memory>
0028 #include <optional>
0029 #include <utility>
0030
0031 namespace clang {
0032
0033 class BinaryOperator;
0034 class CFGBlock;
0035 class DeclRefExpr;
0036 class Expr;
0037 class Stmt;
0038
0039 namespace ento {
0040
0041 class PathSensitiveBugReport;
0042 class BugReporterContext;
0043 class ExplodedNode;
0044 class MemRegion;
0045 class PathDiagnosticPiece;
0046 using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
0047
0048
0049 class BugReporterVisitor : public llvm::FoldingSetNode {
0050 public:
0051 BugReporterVisitor() = default;
0052 BugReporterVisitor(const BugReporterVisitor &) = default;
0053 BugReporterVisitor(BugReporterVisitor &&) {}
0054
0055
0056
0057 BugReporterVisitor &operator=(const BugReporterVisitor &) = delete;
0058 BugReporterVisitor &operator=(BugReporterVisitor &&) = delete;
0059
0060 virtual ~BugReporterVisitor();
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072 virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
0073 BugReporterContext &BRC,
0074 PathSensitiveBugReport &BR) = 0;
0075
0076
0077
0078 virtual void finalizeVisitor(BugReporterContext &BRC,
0079 const ExplodedNode *EndPathNode,
0080 PathSensitiveBugReport &BR);
0081
0082
0083
0084
0085
0086
0087 virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
0088 const ExplodedNode *N,
0089 PathSensitiveBugReport &BR);
0090
0091 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
0092
0093
0094 static PathDiagnosticPieceRef
0095 getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N,
0096 const PathSensitiveBugReport &BR);
0097 };
0098
0099 namespace bugreporter {
0100
0101
0102 enum class TrackingKind {
0103
0104
0105 Thorough,
0106
0107
0108
0109
0110 Condition
0111 };
0112
0113
0114 struct TrackingOptions {
0115
0116 TrackingKind Kind = TrackingKind::Thorough;
0117
0118
0119 bool EnableNullFPSuppression = true;
0120 };
0121
0122
0123
0124
0125
0126
0127 struct StoreInfo {
0128 enum Kind {
0129
0130
0131 Initialization,
0132
0133
0134
0135 Assignment,
0136
0137
0138 CallArgument,
0139
0140
0141
0142
0143 BlockCapture
0144 };
0145
0146
0147 Kind StoreKind;
0148
0149 const ExplodedNode *StoreSite;
0150
0151
0152 const Expr *SourceOfTheValue;
0153
0154 SVal Value;
0155
0156
0157
0158
0159 const MemRegion *Dest, *Origin;
0160 };
0161
0162 class Tracker;
0163 using TrackerRef = llvm::IntrusiveRefCntPtr<Tracker>;
0164
0165 class ExpressionHandler;
0166 class StoreHandler;
0167
0168
0169
0170
0171
0172
0173 class Tracker : public llvm::RefCountedBase<Tracker> {
0174 private:
0175 using ExpressionHandlerPtr = std::unique_ptr<ExpressionHandler>;
0176 using StoreHandlerPtr = std::unique_ptr<StoreHandler>;
0177
0178 PathSensitiveBugReport &Report;
0179 std::list<ExpressionHandlerPtr> ExpressionHandlers;
0180 std::list<StoreHandlerPtr> StoreHandlers;
0181
0182 protected:
0183
0184 Tracker(PathSensitiveBugReport &Report);
0185
0186 public:
0187 virtual ~Tracker() = default;
0188
0189 static TrackerRef create(PathSensitiveBugReport &Report) {
0190 return new Tracker(Report);
0191 }
0192
0193 PathSensitiveBugReport &getReport() { return Report; }
0194
0195
0196
0197 struct Result {
0198
0199 bool FoundSomethingToTrack = false;
0200
0201
0202 bool WasInterrupted = false;
0203
0204
0205 void combineWith(const Result &Other) {
0206
0207
0208 FoundSomethingToTrack |= Other.FoundSomethingToTrack;
0209
0210 WasInterrupted |= Other.WasInterrupted;
0211 }
0212 };
0213
0214
0215
0216
0217
0218
0219 virtual Result track(const Expr *E, const ExplodedNode *N,
0220 TrackingOptions Opts = {});
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235 virtual Result track(SVal V, const MemRegion *R, TrackingOptions Opts = {},
0236 const StackFrameContext *Origin = nullptr);
0237
0238
0239
0240
0241
0242
0243
0244 virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC,
0245 TrackingOptions Opts);
0246
0247
0248
0249
0250
0251 void addHighPriorityHandler(ExpressionHandlerPtr SH) {
0252 ExpressionHandlers.push_front(std::move(SH));
0253 }
0254
0255
0256
0257
0258
0259 void addLowPriorityHandler(ExpressionHandlerPtr SH) {
0260 ExpressionHandlers.push_back(std::move(SH));
0261 }
0262
0263
0264
0265
0266
0267 void addHighPriorityHandler(StoreHandlerPtr SH) {
0268 StoreHandlers.push_front(std::move(SH));
0269 }
0270
0271
0272
0273
0274
0275 void addLowPriorityHandler(StoreHandlerPtr SH) {
0276 StoreHandlers.push_back(std::move(SH));
0277 }
0278
0279
0280
0281
0282 template <class HandlerType, class... Args>
0283 void addHighPriorityHandler(Args &&... ConstructorArgs) {
0284 addHighPriorityHandler(std::make_unique<HandlerType>(
0285 *this, std::forward<Args>(ConstructorArgs)...));
0286 }
0287
0288
0289
0290
0291 template <class HandlerType, class... Args>
0292 void addLowPriorityHandler(Args &&... ConstructorArgs) {
0293 addLowPriorityHandler(std::make_unique<HandlerType>(
0294 *this, std::forward<Args>(ConstructorArgs)...));
0295 }
0296 };
0297
0298
0299 class ExpressionHandler {
0300 private:
0301 Tracker &ParentTracker;
0302
0303 public:
0304 ExpressionHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
0305 virtual ~ExpressionHandler() {}
0306
0307
0308
0309
0310
0311
0312
0313 virtual Tracker::Result handle(const Expr *E, const ExplodedNode *Original,
0314 const ExplodedNode *ExprNode,
0315 TrackingOptions Opts) = 0;
0316
0317
0318 Tracker &getParentTracker() { return ParentTracker; }
0319 };
0320
0321
0322 class StoreHandler {
0323 private:
0324 Tracker &ParentTracker;
0325
0326 public:
0327 StoreHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
0328 virtual ~StoreHandler() {}
0329
0330
0331
0332
0333
0334
0335
0336
0337 virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC,
0338 TrackingOptions Opts) = 0;
0339
0340 Tracker &getParentTracker() { return ParentTracker; }
0341
0342 protected:
0343 PathDiagnosticPieceRef constructNote(StoreInfo SI, BugReporterContext &BRC,
0344 StringRef NodeText);
0345 };
0346
0347
0348 class TrackingBugReporterVisitor : public BugReporterVisitor {
0349 private:
0350 TrackerRef ParentTracker;
0351
0352 public:
0353 TrackingBugReporterVisitor(TrackerRef ParentTracker)
0354 : ParentTracker(ParentTracker) {}
0355
0356 Tracker &getParentTracker() { return *ParentTracker; }
0357 };
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370 bool trackExpressionValue(const ExplodedNode *N, const Expr *E,
0371 PathSensitiveBugReport &R, TrackingOptions Opts = {});
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387 void trackStoredValue(SVal V, const MemRegion *R,
0388 PathSensitiveBugReport &Report, TrackingOptions Opts = {},
0389 const StackFrameContext *Origin = nullptr);
0390
0391 const Expr *getDerefExpr(const Stmt *S);
0392
0393 }
0394
0395 class TrackConstraintBRVisitor final : public BugReporterVisitor {
0396 const SmallString<64> Message;
0397 const DefinedSVal Constraint;
0398 const bool Assumption;
0399 bool IsSatisfied = false;
0400
0401
0402
0403 bool IsTrackingTurnedOn = false;
0404
0405 public:
0406 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption,
0407 StringRef Message)
0408 : Message(Message), Constraint(constraint), Assumption(assumption) {}
0409
0410 void Profile(llvm::FoldingSetNodeID &ID) const override;
0411
0412
0413
0414 static const char *getTag();
0415
0416 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0417 BugReporterContext &BRC,
0418 PathSensitiveBugReport &BR) override;
0419
0420 private:
0421
0422 bool isZeroCheck() const;
0423
0424
0425 bool isUnderconstrained(const ExplodedNode *N) const;
0426 };
0427
0428
0429
0430 class NilReceiverBRVisitor final : public BugReporterVisitor {
0431 public:
0432 void Profile(llvm::FoldingSetNodeID &ID) const override {
0433 static int x = 0;
0434 ID.AddPointer(&x);
0435 }
0436
0437 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0438 BugReporterContext &BRC,
0439 PathSensitiveBugReport &BR) override;
0440
0441
0442
0443 static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
0444 };
0445
0446
0447 class ConditionBRVisitor final : public BugReporterVisitor {
0448
0449 constexpr static llvm::StringLiteral GenericTrueMessage =
0450 "Assuming the condition is true";
0451 constexpr static llvm::StringLiteral GenericFalseMessage =
0452 "Assuming the condition is false";
0453
0454 public:
0455 void Profile(llvm::FoldingSetNodeID &ID) const override {
0456 static int x = 0;
0457 ID.AddPointer(&x);
0458 }
0459
0460
0461
0462 static const char *getTag();
0463
0464 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0465 BugReporterContext &BRC,
0466 PathSensitiveBugReport &BR) override;
0467
0468 PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N,
0469 BugReporterContext &BRC,
0470 PathSensitiveBugReport &BR);
0471
0472 PathDiagnosticPieceRef
0473 VisitTerminator(const Stmt *Term, const ExplodedNode *N,
0474 const CFGBlock *SrcBlk, const CFGBlock *DstBlk,
0475 PathSensitiveBugReport &R, BugReporterContext &BRC);
0476
0477 PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond,
0478 BugReporterContext &BRC,
0479 PathSensitiveBugReport &R,
0480 const ExplodedNode *N, bool TookTrue);
0481
0482 PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR,
0483 BugReporterContext &BRC,
0484 PathSensitiveBugReport &R,
0485 const ExplodedNode *N, bool TookTrue,
0486 bool IsAssuming);
0487
0488 PathDiagnosticPieceRef
0489 VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
0490 BugReporterContext &BRC, PathSensitiveBugReport &R,
0491 const ExplodedNode *N, bool TookTrue, bool IsAssuming);
0492
0493 PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const MemberExpr *ME,
0494 BugReporterContext &BRC,
0495 PathSensitiveBugReport &R,
0496 const ExplodedNode *N, bool TookTrue,
0497 bool IsAssuming);
0498
0499 PathDiagnosticPieceRef
0500 VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
0501 BugReporterContext &BRC, PathSensitiveBugReport &R,
0502 const ExplodedNode *N, bool TookTrue);
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513 bool printValue(const Expr *CondVarExpr, raw_ostream &Out,
0514 const ExplodedNode *N, bool TookTrue, bool IsAssuming);
0515
0516 bool patternMatch(const Expr *Ex, const Expr *ParentEx, raw_ostream &Out,
0517 BugReporterContext &BRC, PathSensitiveBugReport &R,
0518 const ExplodedNode *N, std::optional<bool> &prunable,
0519 bool IsSameFieldName);
0520
0521 static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece);
0522 };
0523
0524
0525
0526
0527 class LikelyFalsePositiveSuppressionBRVisitor final
0528 : public BugReporterVisitor {
0529 public:
0530 static void *getTag() {
0531 static int Tag = 0;
0532 return static_cast<void *>(&Tag);
0533 }
0534
0535 void Profile(llvm::FoldingSetNodeID &ID) const override {
0536 ID.AddPointer(getTag());
0537 }
0538
0539 PathDiagnosticPieceRef VisitNode(const ExplodedNode *, BugReporterContext &,
0540 PathSensitiveBugReport &) override {
0541 return nullptr;
0542 }
0543
0544 void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
0545 PathSensitiveBugReport &BR) override;
0546 };
0547
0548
0549
0550
0551
0552
0553 class UndefOrNullArgVisitor final : public BugReporterVisitor {
0554
0555 const MemRegion *R;
0556
0557 public:
0558 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
0559
0560 void Profile(llvm::FoldingSetNodeID &ID) const override {
0561 static int Tag = 0;
0562 ID.AddPointer(&Tag);
0563 ID.AddPointer(R);
0564 }
0565
0566 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0567 BugReporterContext &BRC,
0568 PathSensitiveBugReport &BR) override;
0569 };
0570
0571 class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {
0572
0573
0574 DefinedSVal V;
0575
0576
0577 bool IsSatisfied = false;
0578
0579
0580
0581
0582
0583
0584 bool IsTrackingTurnedOn = false;
0585
0586 public:
0587 SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
0588
0589 void Profile(llvm::FoldingSetNodeID &ID) const override;
0590
0591
0592
0593 static const char *getTag();
0594
0595 PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
0596 BugReporterContext &BRC,
0597 PathSensitiveBugReport &BR) override;
0598 };
0599
0600
0601 class TagVisitor : public BugReporterVisitor {
0602 public:
0603 void Profile(llvm::FoldingSetNodeID &ID) const override;
0604
0605 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0606 BugReporterContext &BRC,
0607 PathSensitiveBugReport &R) override;
0608 };
0609
0610 class ObjCMethodCall;
0611 class CXXConstructorCall;
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623 class NoStateChangeFuncVisitor : public BugReporterVisitor {
0624 private:
0625
0626
0627
0628
0629
0630
0631
0632
0633
0634
0635 llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifying;
0636 llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifyingCalculated;
0637
0638
0639
0640
0641 bool isModifiedInFrame(const ExplodedNode *CallExitBeginN);
0642
0643 void markFrameAsModifying(const StackFrameContext *SCtx);
0644
0645
0646
0647 void findModifyingFrames(const ExplodedNode *const CallExitBeginN);
0648
0649 protected:
0650 bugreporter::TrackingKind TKind;
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661 virtual bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
0662 const ExplodedNode *CallExitBeginN) {
0663 return false;
0664 }
0665
0666
0667
0668
0669
0670
0671
0672
0673
0674
0675
0676
0677
0678
0679 virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN,
0680 const ExplodedNode *CallExitEndN) {
0681 return false;
0682 }
0683
0684
0685
0686
0687
0688
0689 virtual PathDiagnosticPieceRef
0690 maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
0691 const ObjCMethodCall &Call,
0692 const ExplodedNode *N) = 0;
0693
0694
0695
0696
0697
0698
0699 virtual PathDiagnosticPieceRef
0700 maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
0701 const CXXConstructorCall &Call,
0702 const ExplodedNode *N) = 0;
0703
0704
0705
0706
0707
0708
0709 virtual PathDiagnosticPieceRef
0710 maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
0711 const ExplodedNode *N) = 0;
0712
0713 public:
0714 NoStateChangeFuncVisitor(bugreporter::TrackingKind TKind) : TKind(TKind) {}
0715
0716 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
0717 BugReporterContext &BR,
0718 PathSensitiveBugReport &R) final;
0719 };
0720
0721
0722
0723
0724
0725 class NoStoreFuncVisitor final : public NoStateChangeFuncVisitor {
0726 const SubRegion *RegionOfInterest;
0727 MemRegionManager &MmrMgr;
0728 const SourceManager &SM;
0729 const PrintingPolicy &PP;
0730
0731
0732
0733
0734 static const unsigned DEREFERENCE_LIMIT = 2;
0735
0736 using RegionVector = SmallVector<const MemRegion *, 5>;
0737
0738 public:
0739 NoStoreFuncVisitor(
0740 const SubRegion *R,
0741 bugreporter::TrackingKind TKind = bugreporter::TrackingKind::Thorough)
0742 : NoStateChangeFuncVisitor(TKind), RegionOfInterest(R),
0743 MmrMgr(R->getMemRegionManager()),
0744 SM(MmrMgr.getContext().getSourceManager()),
0745 PP(MmrMgr.getContext().getPrintingPolicy()) {}
0746
0747 void Profile(llvm::FoldingSetNodeID &ID) const override {
0748 static int Tag = 0;
0749 ID.AddPointer(&Tag);
0750 ID.AddPointer(RegionOfInterest);
0751 }
0752
0753 private:
0754
0755
0756 bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
0757 const ExplodedNode *CallExitBeginN) override;
0758
0759
0760
0761
0762
0763
0764
0765 const std::optional<RegionVector>
0766 findRegionOfInterestInRecord(const RecordDecl *RD, ProgramStateRef State,
0767 const MemRegion *R, const RegionVector &Vec = {},
0768 int depth = 0);
0769
0770
0771
0772 PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
0773 const ObjCMethodCall &Call,
0774 const ExplodedNode *N) final;
0775
0776 PathDiagnosticPieceRef maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
0777 const CXXConstructorCall &Call,
0778 const ExplodedNode *N) final;
0779
0780 PathDiagnosticPieceRef
0781 maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
0782 const ExplodedNode *N) final;
0783
0784
0785
0786
0787
0788 PathDiagnosticPieceRef
0789 maybeEmitNote(PathSensitiveBugReport &R, const CallEvent &Call,
0790 const ExplodedNode *N, const RegionVector &FieldChain,
0791 const MemRegion *MatchedRegion, StringRef FirstElement,
0792 bool FirstIsReferenceType, unsigned IndirectionLevel);
0793
0794 bool prettyPrintRegionName(const RegionVector &FieldChain,
0795 const MemRegion *MatchedRegion,
0796 StringRef FirstElement, bool FirstIsReferenceType,
0797 unsigned IndirectionLevel,
0798 llvm::raw_svector_ostream &os);
0799
0800 StringRef prettyPrintFirstElement(StringRef FirstElement,
0801 bool MoreItemsExpected,
0802 int IndirectionLevel,
0803 llvm::raw_svector_ostream &os);
0804 };
0805
0806 }
0807 }
0808
0809 #endif