1 //===--- BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines BugReporter, a utility class for generating 11 // PathDiagnostics for analyses based on ProgramState. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H 16 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H 17 18 #include "clang/Basic/SourceLocation.h" 19 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" 20 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" 21 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 22 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 24 #include "llvm/ADT/DenseSet.h" 25 #include "llvm/ADT/FoldingSet.h" 26 #include "llvm/ADT/ImmutableSet.h" 27 #include "llvm/ADT/SmallSet.h" 28 #include "llvm/ADT/ilist.h" 29 #include "llvm/ADT/ilist_node.h" 30 31 namespace clang { 32 33 class ASTContext; 34 class DiagnosticsEngine; 35 class Stmt; 36 class ParentMap; 37 38 namespace ento { 39 40 class PathDiagnostic; 41 class ExplodedNode; 42 class ExplodedGraph; 43 class BugReport; 44 class BugReporter; 45 class BugReporterContext; 46 class ExprEngine; 47 class BugType; 48 49 //===----------------------------------------------------------------------===// 50 // Interface for individual bug reports. 51 //===----------------------------------------------------------------------===// 52 53 /// This class provides an interface through which checkers can create 54 /// individual bug reports. 55 class BugReport : public llvm::ilist_node<BugReport> { 56 public: 57 class NodeResolver { 58 virtual void anchor(); 59 public: 60 virtual ~NodeResolver() {} 61 virtual const ExplodedNode* 62 getOriginalNode(const ExplodedNode *N) = 0; 63 }; 64 65 typedef const SourceRange *ranges_iterator; 66 typedef SmallVector<std::unique_ptr<BugReporterVisitor>, 8> VisitorList; 67 typedef VisitorList::iterator visitor_iterator; 68 typedef SmallVector<StringRef, 2> ExtraTextList; 69 typedef SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4> NoteList; 70 71 protected: 72 friend class BugReporter; 73 friend class BugReportEquivClass; 74 75 BugType& BT; 76 const Decl *DeclWithIssue; 77 std::string ShortDescription; 78 std::string Description; 79 PathDiagnosticLocation Location; 80 PathDiagnosticLocation UniqueingLocation; 81 const Decl *UniqueingDecl; 82 83 const ExplodedNode *ErrorNode; 84 SmallVector<SourceRange, 4> Ranges; 85 ExtraTextList ExtraText; 86 NoteList Notes; 87 88 typedef llvm::DenseSet<SymbolRef> Symbols; 89 typedef llvm::DenseSet<const MemRegion *> Regions; 90 91 /// A (stack of) a set of symbols that are registered with this 92 /// report as being "interesting", and thus used to help decide which 93 /// diagnostics to include when constructing the final path diagnostic. 94 /// The stack is largely used by BugReporter when generating PathDiagnostics 95 /// for multiple PathDiagnosticConsumers. 96 SmallVector<Symbols *, 2> interestingSymbols; 97 98 /// A (stack of) set of regions that are registered with this report as being 99 /// "interesting", and thus used to help decide which diagnostics 100 /// to include when constructing the final path diagnostic. 101 /// The stack is largely used by BugReporter when generating PathDiagnostics 102 /// for multiple PathDiagnosticConsumers. 103 SmallVector<Regions *, 2> interestingRegions; 104 105 /// A set of location contexts that correspoind to call sites which should be 106 /// considered "interesting". 107 llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts; 108 109 /// A set of custom visitors which generate "event" diagnostics at 110 /// interesting points in the path. 111 VisitorList Callbacks; 112 113 /// Used for ensuring the visitors are only added once. 114 llvm::FoldingSet<BugReporterVisitor> CallbacksSet; 115 116 /// Used for clients to tell if the report's configuration has changed 117 /// since the last time they checked. 118 unsigned ConfigurationChangeToken; 119 120 /// When set, this flag disables all callstack pruning from a diagnostic 121 /// path. This is useful for some reports that want maximum fidelty 122 /// when reporting an issue. 123 bool DoNotPrunePath; 124 125 /// Used to track unique reasons why a bug report might be invalid. 126 /// 127 /// \sa markInvalid 128 /// \sa removeInvalidation 129 typedef std::pair<const void *, const void *> InvalidationRecord; 130 131 /// If non-empty, this bug report is likely a false positive and should not be 132 /// shown to the user. 133 /// 134 /// \sa markInvalid 135 /// \sa removeInvalidation 136 llvm::SmallSet<InvalidationRecord, 4> Invalidations; 137 138 private: 139 // Used internally by BugReporter. 140 Symbols &getInterestingSymbols(); 141 Regions &getInterestingRegions(); 142 143 void lazyInitializeInterestingSets(); 144 void pushInterestingSymbolsAndRegions(); 145 void popInterestingSymbolsAndRegions(); 146 147 public: 148 BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode) 149 : BT(bt), DeclWithIssue(nullptr), Description(desc), ErrorNode(errornode), 150 ConfigurationChangeToken(0), DoNotPrunePath(false) {} 151 152 BugReport(BugType& bt, StringRef shortDesc, StringRef desc, 153 const ExplodedNode *errornode) 154 : BT(bt), DeclWithIssue(nullptr), ShortDescription(shortDesc), 155 Description(desc), ErrorNode(errornode), ConfigurationChangeToken(0), 156 DoNotPrunePath(false) {} 157 158 BugReport(BugType &bt, StringRef desc, PathDiagnosticLocation l) 159 : BT(bt), DeclWithIssue(nullptr), Description(desc), Location(l), 160 ErrorNode(nullptr), ConfigurationChangeToken(0), DoNotPrunePath(false) {} 161 162 /// \brief Create a BugReport with a custom uniqueing location. 163 /// 164 /// The reports that have the same report location, description, bug type, and 165 /// ranges are uniqued - only one of the equivalent reports will be presented 166 /// to the user. This method allows to rest the location which should be used 167 /// for uniquing reports. For example, memory leaks checker, could set this to 168 /// the allocation site, rather then the location where the bug is reported. 169 BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode, 170 PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique) 171 : BT(bt), DeclWithIssue(nullptr), Description(desc), 172 UniqueingLocation(LocationToUnique), 173 UniqueingDecl(DeclToUnique), 174 ErrorNode(errornode), ConfigurationChangeToken(0), 175 DoNotPrunePath(false) {} 176 177 virtual ~BugReport(); 178 179 const BugType& getBugType() const { return BT; } 180 BugType& getBugType() { return BT; } 181 182 /// \brief True when the report has an execution path associated with it. 183 /// 184 /// A report is said to be path-sensitive if it was thrown against a 185 /// particular exploded node in the path-sensitive analysis graph. 186 /// Path-sensitive reports have their intermediate path diagnostics 187 /// auto-generated, perhaps with the help of checker-defined visitors, 188 /// and may contain extra notes. 189 /// Path-insensitive reports consist only of a single warning message 190 /// in a specific location, and perhaps extra notes. 191 /// Path-sensitive checkers are allowed to throw path-insensitive reports. 192 bool isPathSensitive() const { return ErrorNode != nullptr; } 193 194 const ExplodedNode *getErrorNode() const { return ErrorNode; } 195 196 StringRef getDescription() const { return Description; } 197 198 StringRef getShortDescription(bool UseFallback = true) const { 199 if (ShortDescription.empty() && UseFallback) 200 return Description; 201 return ShortDescription; 202 } 203 204 /// Indicates whether or not any path pruning should take place 205 /// when generating a PathDiagnostic from this BugReport. 206 bool shouldPrunePath() const { return !DoNotPrunePath; } 207 208 /// Disable all path pruning when generating a PathDiagnostic. 209 void disablePathPruning() { DoNotPrunePath = true; } 210 211 void markInteresting(SymbolRef sym); 212 void markInteresting(const MemRegion *R); 213 void markInteresting(SVal V); 214 void markInteresting(const LocationContext *LC); 215 216 bool isInteresting(SymbolRef sym); 217 bool isInteresting(const MemRegion *R); 218 bool isInteresting(SVal V); 219 bool isInteresting(const LocationContext *LC); 220 221 unsigned getConfigurationChangeToken() const { 222 return ConfigurationChangeToken; 223 } 224 225 /// Returns whether or not this report should be considered valid. 226 /// 227 /// Invalid reports are those that have been classified as likely false 228 /// positives after the fact. 229 bool isValid() const { 230 return Invalidations.empty(); 231 } 232 233 /// Marks the current report as invalid, meaning that it is probably a false 234 /// positive and should not be reported to the user. 235 /// 236 /// The \p Tag and \p Data arguments are intended to be opaque identifiers for 237 /// this particular invalidation, where \p Tag represents the visitor 238 /// responsible for invalidation, and \p Data represents the reason this 239 /// visitor decided to invalidate the bug report. 240 /// 241 /// \sa removeInvalidation 242 void markInvalid(const void *Tag, const void *Data) { 243 Invalidations.insert(std::make_pair(Tag, Data)); 244 } 245 246 /// Reverses the effects of a previous invalidation. 247 /// 248 /// \sa markInvalid 249 void removeInvalidation(const void *Tag, const void *Data) { 250 Invalidations.erase(std::make_pair(Tag, Data)); 251 } 252 253 /// Return the canonical declaration, be it a method or class, where 254 /// this issue semantically occurred. 255 const Decl *getDeclWithIssue() const; 256 257 /// Specifically set the Decl where an issue occurred. This isn't necessary 258 /// for BugReports that cover a path as it will be automatically inferred. 259 void setDeclWithIssue(const Decl *declWithIssue) { 260 DeclWithIssue = declWithIssue; 261 } 262 263 /// Add new item to the list of additional notes that need to be attached to 264 /// this path-insensitive report. If you want to add extra notes to a 265 /// path-sensitive report, you need to use a BugReporterVisitor because it 266 /// allows you to specify where exactly in the auto-generated path diagnostic 267 /// the extra note should appear. 268 void addNote(StringRef Msg, const PathDiagnosticLocation &Pos, 269 ArrayRef<SourceRange> Ranges) { 270 auto P = std::make_shared<PathDiagnosticNotePiece>(Pos, Msg); 271 272 for (const auto &R : Ranges) 273 P->addRange(R); 274 275 Notes.push_back(std::move(P)); 276 } 277 278 // FIXME: Instead of making an override, we could have default-initialized 279 // Ranges with {}, however it crashes the MSVC 2013 compiler. 280 void addNote(StringRef Msg, const PathDiagnosticLocation &Pos) { 281 std::vector<SourceRange> Ranges; 282 addNote(Msg, Pos, Ranges); 283 } 284 285 virtual const NoteList &getNotes() { 286 return Notes; 287 } 288 289 /// \brief This allows for addition of meta data to the diagnostic. 290 /// 291 /// Currently, only the HTMLDiagnosticClient knows how to display it. 292 void addExtraText(StringRef S) { 293 ExtraText.push_back(S); 294 } 295 296 virtual const ExtraTextList &getExtraText() { 297 return ExtraText; 298 } 299 300 /// \brief Return the "definitive" location of the reported bug. 301 /// 302 /// While a bug can span an entire path, usually there is a specific 303 /// location that can be used to identify where the key issue occurred. 304 /// This location is used by clients rendering diagnostics. 305 virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const; 306 307 /// \brief Get the location on which the report should be uniqued. 308 PathDiagnosticLocation getUniqueingLocation() const { 309 return UniqueingLocation; 310 } 311 312 /// \brief Get the declaration containing the uniqueing location. 313 const Decl *getUniqueingDecl() const { 314 return UniqueingDecl; 315 } 316 317 const Stmt *getStmt() const; 318 319 /// \brief Add a range to a bug report. 320 /// 321 /// Ranges are used to highlight regions of interest in the source code. 322 /// They should be at the same source code line as the BugReport location. 323 /// By default, the source range of the statement corresponding to the error 324 /// node will be used; add a single invalid range to specify absence of 325 /// ranges. 326 void addRange(SourceRange R) { 327 assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used " 328 "to specify that the report does not have a range."); 329 Ranges.push_back(R); 330 } 331 332 /// \brief Get the SourceRanges associated with the report. 333 virtual llvm::iterator_range<ranges_iterator> getRanges(); 334 335 /// \brief Add custom or predefined bug report visitors to this report. 336 /// 337 /// The visitors should be used when the default trace is not sufficient. 338 /// For example, they allow constructing a more elaborate trace. 339 /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(), 340 /// registerFindLastStore(), registerNilReceiverVisitor(), and 341 /// registerVarDeclsLastStore(). 342 void addVisitor(std::unique_ptr<BugReporterVisitor> visitor); 343 344 /// Iterators through the custom diagnostic visitors. 345 visitor_iterator visitor_begin() { return Callbacks.begin(); } 346 visitor_iterator visitor_end() { return Callbacks.end(); } 347 348 /// Profile to identify equivalent bug reports for error report coalescing. 349 /// Reports are uniqued to ensure that we do not emit multiple diagnostics 350 /// for each bug. 351 virtual void Profile(llvm::FoldingSetNodeID& hash) const; 352 }; 353 354 //===----------------------------------------------------------------------===// 355 // BugTypes (collections of related reports). 356 //===----------------------------------------------------------------------===// 357 358 class BugReportEquivClass : public llvm::FoldingSetNode { 359 /// List of *owned* BugReport objects. 360 llvm::ilist<BugReport> Reports; 361 362 friend class BugReporter; 363 void AddReport(std::unique_ptr<BugReport> R) { 364 Reports.push_back(R.release()); 365 } 366 367 public: 368 BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); } 369 ~BugReportEquivClass(); 370 371 void Profile(llvm::FoldingSetNodeID& ID) const { 372 assert(!Reports.empty()); 373 Reports.front().Profile(ID); 374 } 375 376 typedef llvm::ilist<BugReport>::iterator iterator; 377 typedef llvm::ilist<BugReport>::const_iterator const_iterator; 378 379 iterator begin() { return Reports.begin(); } 380 iterator end() { return Reports.end(); } 381 382 const_iterator begin() const { return Reports.begin(); } 383 const_iterator end() const { return Reports.end(); } 384 }; 385 386 //===----------------------------------------------------------------------===// 387 // BugReporter and friends. 388 //===----------------------------------------------------------------------===// 389 390 class BugReporterData { 391 public: 392 virtual ~BugReporterData(); 393 virtual DiagnosticsEngine& getDiagnostic() = 0; 394 virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0; 395 virtual ASTContext &getASTContext() = 0; 396 virtual SourceManager& getSourceManager() = 0; 397 virtual AnalyzerOptions& getAnalyzerOptions() = 0; 398 }; 399 400 /// BugReporter is a utility class for generating PathDiagnostics for analysis. 401 /// It collects the BugReports and BugTypes and knows how to generate 402 /// and flush the corresponding diagnostics. 403 class BugReporter { 404 public: 405 enum Kind { BaseBRKind, GRBugReporterKind }; 406 407 private: 408 typedef llvm::ImmutableSet<BugType*> BugTypesTy; 409 BugTypesTy::Factory F; 410 BugTypesTy BugTypes; 411 412 const Kind kind; 413 BugReporterData& D; 414 415 /// Generate and flush the diagnostics for the given bug report. 416 void FlushReport(BugReportEquivClass& EQ); 417 418 /// Generate and flush the diagnostics for the given bug report 419 /// and PathDiagnosticConsumer. 420 void FlushReport(BugReport *exampleReport, 421 PathDiagnosticConsumer &PD, 422 ArrayRef<BugReport*> BugReports); 423 424 /// The set of bug reports tracked by the BugReporter. 425 llvm::FoldingSet<BugReportEquivClass> EQClasses; 426 /// A vector of BugReports for tracking the allocated pointers and cleanup. 427 std::vector<BugReportEquivClass *> EQClassesVector; 428 429 protected: 430 BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k), 431 D(d) {} 432 433 public: 434 BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind), 435 D(d) {} 436 virtual ~BugReporter(); 437 438 /// \brief Generate and flush diagnostics for all bug reports. 439 void FlushReports(); 440 441 Kind getKind() const { return kind; } 442 443 DiagnosticsEngine& getDiagnostic() { 444 return D.getDiagnostic(); 445 } 446 447 ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() { 448 return D.getPathDiagnosticConsumers(); 449 } 450 451 /// \brief Iterator over the set of BugTypes tracked by the BugReporter. 452 typedef BugTypesTy::iterator iterator; 453 iterator begin() { return BugTypes.begin(); } 454 iterator end() { return BugTypes.end(); } 455 456 /// \brief Iterator over the set of BugReports tracked by the BugReporter. 457 typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator; 458 EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); } 459 EQClasses_iterator EQClasses_end() { return EQClasses.end(); } 460 461 ASTContext &getContext() { return D.getASTContext(); } 462 463 SourceManager& getSourceManager() { return D.getSourceManager(); } 464 465 AnalyzerOptions& getAnalyzerOptions() { return D.getAnalyzerOptions(); } 466 467 virtual bool generatePathDiagnostic(PathDiagnostic& pathDiagnostic, 468 PathDiagnosticConsumer &PC, 469 ArrayRef<BugReport *> &bugReports) { 470 return true; 471 } 472 473 bool RemoveUnneededCalls(PathPieces &pieces, BugReport *R); 474 475 void Register(BugType *BT); 476 477 /// \brief Add the given report to the set of reports tracked by BugReporter. 478 /// 479 /// The reports are usually generated by the checkers. Further, they are 480 /// folded based on the profile value, which is done to coalesce similar 481 /// reports. 482 void emitReport(std::unique_ptr<BugReport> R); 483 484 void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, 485 StringRef BugName, StringRef BugCategory, 486 StringRef BugStr, PathDiagnosticLocation Loc, 487 ArrayRef<SourceRange> Ranges = None); 488 489 void EmitBasicReport(const Decl *DeclWithIssue, CheckName CheckName, 490 StringRef BugName, StringRef BugCategory, 491 StringRef BugStr, PathDiagnosticLocation Loc, 492 ArrayRef<SourceRange> Ranges = None); 493 494 private: 495 llvm::StringMap<BugType *> StrBugTypes; 496 497 /// \brief Returns a BugType that is associated with the given name and 498 /// category. 499 BugType *getBugTypeForName(CheckName CheckName, StringRef name, 500 StringRef category); 501 }; 502 503 // FIXME: Get rid of GRBugReporter. It's the wrong abstraction. 504 class GRBugReporter : public BugReporter { 505 ExprEngine& Eng; 506 public: 507 GRBugReporter(BugReporterData& d, ExprEngine& eng) 508 : BugReporter(d, GRBugReporterKind), Eng(eng) {} 509 510 ~GRBugReporter() override; 511 512 /// getEngine - Return the analysis engine used to analyze a given 513 /// function or method. 514 ExprEngine &getEngine() { return Eng; } 515 516 /// getGraph - Get the exploded graph created by the analysis engine 517 /// for the analyzed method or function. 518 ExplodedGraph &getGraph(); 519 520 /// getStateManager - Return the state manager used by the analysis 521 /// engine. 522 ProgramStateManager &getStateManager(); 523 524 /// Generates a path corresponding to one of the given bug reports. 525 /// 526 /// Which report is used for path generation is not specified. The 527 /// bug reporter will try to pick the shortest path, but this is not 528 /// guaranteed. 529 /// 530 /// \return True if the report was valid and a path was generated, 531 /// false if the reports should be considered invalid. 532 bool generatePathDiagnostic(PathDiagnostic &PD, PathDiagnosticConsumer &PC, 533 ArrayRef<BugReport*> &bugReports) override; 534 535 /// classof - Used by isa<>, cast<>, and dyn_cast<>. 536 static bool classof(const BugReporter* R) { 537 return R->getKind() == GRBugReporterKind; 538 } 539 }; 540 541 class BugReporterContext { 542 virtual void anchor(); 543 GRBugReporter &BR; 544 public: 545 BugReporterContext(GRBugReporter& br) : BR(br) {} 546 547 virtual ~BugReporterContext() {} 548 549 GRBugReporter& getBugReporter() { return BR; } 550 551 ExplodedGraph &getGraph() { return BR.getGraph(); } 552 553 ProgramStateManager& getStateManager() { 554 return BR.getStateManager(); 555 } 556 557 SValBuilder& getSValBuilder() { 558 return getStateManager().getSValBuilder(); 559 } 560 561 ASTContext &getASTContext() { 562 return BR.getContext(); 563 } 564 565 SourceManager& getSourceManager() { 566 return BR.getSourceManager(); 567 } 568 569 virtual BugReport::NodeResolver& getNodeResolver() = 0; 570 }; 571 572 } // end GR namespace 573 574 } // end clang namespace 575 576 #endif 577