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