Home | History | Annotate | Download | only in BugReporter
      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