clang API Documentation

BugReporterVisitor.h
Go to the documentation of this file.
00001 //===---  BugReporterVisitor.h - Generate PathDiagnostics -------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file declares BugReporterVisitors, which are used to generate enhanced
00011 //  diagnostic traces.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H
00016 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H
00017 
00018 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
00019 #include "llvm/ADT/FoldingSet.h"
00020 
00021 namespace clang {
00022 
00023 namespace ento {
00024 
00025 class BugReport;
00026 class BugReporterContext;
00027 class ExplodedNode;
00028 class MemRegion;
00029 class PathDiagnosticPiece;
00030 
00031 /// \brief BugReporterVisitors are used to add custom diagnostics along a path.
00032 ///
00033 /// Custom visitors should subclass the BugReporterVisitorImpl class for a
00034 /// default implementation of the clone() method.
00035 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
00036 /// default implementation of clone() will NOT do the right thing, and you
00037 /// will have to provide your own implementation.)
00038 class BugReporterVisitor : public llvm::FoldingSetNode {
00039 public:
00040   virtual ~BugReporterVisitor();
00041 
00042   /// \brief Returns a copy of this BugReporter.
00043   ///
00044   /// Custom BugReporterVisitors should not override this method directly.
00045   /// Instead, they should inherit from BugReporterVisitorImpl and provide
00046   /// a protected or public copy constructor.
00047   ///
00048   /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
00049   /// default implementation of clone() will NOT do the right thing, and you
00050   /// will have to provide your own implementation.)
00051   virtual std::unique_ptr<BugReporterVisitor> clone() const = 0;
00052 
00053   /// \brief Return a diagnostic piece which should be associated with the
00054   /// given node.
00055   ///
00056   /// The last parameter can be used to register a new visitor with the given
00057   /// BugReport while processing a node.
00058   virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
00059                                          const ExplodedNode *Pred,
00060                                          BugReporterContext &BRC,
00061                                          BugReport &BR) = 0;
00062 
00063   /// \brief Provide custom definition for the final diagnostic piece on the
00064   /// path - the piece, which is displayed before the path is expanded.
00065   ///
00066   /// If returns NULL the default implementation will be used.
00067   /// Also note that at most one visitor of a BugReport should generate a
00068   /// non-NULL end of path diagnostic piece.
00069   virtual std::unique_ptr<PathDiagnosticPiece>
00070   getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR);
00071 
00072   virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
00073 
00074   /// \brief Generates the default final diagnostic piece.
00075   static std::unique_ptr<PathDiagnosticPiece>
00076   getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N,
00077                     BugReport &BR);
00078 };
00079 
00080 /// This class provides a convenience implementation for clone() using the
00081 /// Curiously-Recurring Template Pattern. If you are implementing a custom
00082 /// BugReporterVisitor, subclass BugReporterVisitorImpl and provide a public
00083 /// or protected copy constructor.
00084 ///
00085 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
00086 /// default implementation of clone() will NOT do the right thing, and you
00087 /// will have to provide your own implementation.)
00088 template <class DERIVED>
00089 class BugReporterVisitorImpl : public BugReporterVisitor {
00090   std::unique_ptr<BugReporterVisitor> clone() const override {
00091     return llvm::make_unique<DERIVED>(*static_cast<const DERIVED *>(this));
00092   }
00093 };
00094 
00095 class FindLastStoreBRVisitor
00096   : public BugReporterVisitorImpl<FindLastStoreBRVisitor>
00097 {
00098   const MemRegion *R;
00099   SVal V;
00100   bool Satisfied;
00101 
00102   /// If the visitor is tracking the value directly responsible for the
00103   /// bug, we are going to employ false positive suppression.
00104   bool EnableNullFPSuppression;
00105 
00106 public:
00107   /// Creates a visitor for every VarDecl inside a Stmt and registers it with
00108   /// the BugReport.
00109   static void registerStatementVarDecls(BugReport &BR, const Stmt *S,
00110                                         bool EnableNullFPSuppression);
00111 
00112   FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
00113                          bool InEnableNullFPSuppression)
00114   : R(R),
00115     V(V),
00116     Satisfied(false),
00117     EnableNullFPSuppression(InEnableNullFPSuppression) {}
00118 
00119   void Profile(llvm::FoldingSetNodeID &ID) const override;
00120 
00121   PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
00122                                  const ExplodedNode *PrevN,
00123                                  BugReporterContext &BRC,
00124                                  BugReport &BR) override;
00125 };
00126 
00127 class TrackConstraintBRVisitor
00128   : public BugReporterVisitorImpl<TrackConstraintBRVisitor>
00129 {
00130   DefinedSVal Constraint;
00131   bool Assumption;
00132   bool IsSatisfied;
00133   bool IsZeroCheck;
00134 
00135   /// We should start tracking from the last node along the path in which the
00136   /// value is constrained.
00137   bool IsTrackingTurnedOn;
00138 
00139 public:
00140   TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
00141   : Constraint(constraint), Assumption(assumption), IsSatisfied(false),
00142     IsZeroCheck(!Assumption && Constraint.getAs<Loc>()),
00143     IsTrackingTurnedOn(false) {}
00144 
00145   void Profile(llvm::FoldingSetNodeID &ID) const override;
00146 
00147   /// Return the tag associated with this visitor.  This tag will be used
00148   /// to make all PathDiagnosticPieces created by this visitor.
00149   static const char *getTag();
00150 
00151   PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
00152                                  const ExplodedNode *PrevN,
00153                                  BugReporterContext &BRC,
00154                                  BugReport &BR) override;
00155 
00156 private:
00157   /// Checks if the constraint is valid in the current state.
00158   bool isUnderconstrained(const ExplodedNode *N) const;
00159 
00160 };
00161 
00162 /// \class NilReceiverBRVisitor
00163 /// \brief Prints path notes when a message is sent to a nil receiver.
00164 class NilReceiverBRVisitor
00165   : public BugReporterVisitorImpl<NilReceiverBRVisitor> {
00166 public:
00167 
00168   void Profile(llvm::FoldingSetNodeID &ID) const override {
00169     static int x = 0;
00170     ID.AddPointer(&x);
00171   }
00172 
00173   PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
00174                                  const ExplodedNode *PrevN,
00175                                  BugReporterContext &BRC,
00176                                  BugReport &BR) override;
00177 
00178   /// If the statement is a message send expression with nil receiver, returns
00179   /// the receiver expression. Returns NULL otherwise.
00180   static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
00181 };
00182 
00183 /// Visitor that tries to report interesting diagnostics from conditions.
00184 class ConditionBRVisitor : public BugReporterVisitorImpl<ConditionBRVisitor> {
00185 public:
00186   void Profile(llvm::FoldingSetNodeID &ID) const override {
00187     static int x = 0;
00188     ID.AddPointer(&x);
00189   }
00190 
00191   /// Return the tag associated with this visitor.  This tag will be used
00192   /// to make all PathDiagnosticPieces created by this visitor.
00193   static const char *getTag();
00194 
00195   PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
00196                                  const ExplodedNode *Prev,
00197                                  BugReporterContext &BRC,
00198                                  BugReport &BR) override;
00199 
00200   PathDiagnosticPiece *VisitNodeImpl(const ExplodedNode *N,
00201                                      const ExplodedNode *Prev,
00202                                      BugReporterContext &BRC,
00203                                      BugReport &BR);
00204   
00205   PathDiagnosticPiece *VisitTerminator(const Stmt *Term,
00206                                        const ExplodedNode *N,
00207                                        const CFGBlock *srcBlk,
00208                                        const CFGBlock *dstBlk,
00209                                        BugReport &R,
00210                                        BugReporterContext &BRC);
00211 
00212   PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
00213                                      bool tookTrue,
00214                                      BugReporterContext &BRC,
00215                                      BugReport &R,
00216                                      const ExplodedNode *N);
00217 
00218   PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
00219                                      const DeclRefExpr *DR,
00220                                      const bool tookTrue,
00221                                      BugReporterContext &BRC,
00222                                      BugReport &R,
00223                                      const ExplodedNode *N);
00224 
00225   PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
00226                                      const BinaryOperator *BExpr,
00227                                      const bool tookTrue,
00228                                      BugReporterContext &BRC,
00229                                      BugReport &R,
00230                                      const ExplodedNode *N);
00231   
00232   PathDiagnosticPiece *VisitConditionVariable(StringRef LhsString,
00233                                               const Expr *CondVarExpr,
00234                                               const bool tookTrue,
00235                                               BugReporterContext &BRC,
00236                                               BugReport &R,
00237                                               const ExplodedNode *N);
00238 
00239   bool patternMatch(const Expr *Ex,
00240                     raw_ostream &Out,
00241                     BugReporterContext &BRC,
00242                     BugReport &R,
00243                     const ExplodedNode *N,
00244                     Optional<bool> &prunable);
00245 };
00246 
00247 /// \brief Suppress reports that might lead to known false positives.
00248 ///
00249 /// Currently this suppresses reports based on locations of bugs.
00250 class LikelyFalsePositiveSuppressionBRVisitor
00251   : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> {
00252 public:
00253   static void *getTag() {
00254     static int Tag = 0;
00255     return static_cast<void *>(&Tag);
00256   }
00257 
00258   void Profile(llvm::FoldingSetNodeID &ID) const override {
00259     ID.AddPointer(getTag());
00260   }
00261 
00262   PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
00263                                  const ExplodedNode *Prev,
00264                                  BugReporterContext &BRC,
00265                                  BugReport &BR) override {
00266     return nullptr;
00267   }
00268 
00269   std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
00270                                                   const ExplodedNode *N,
00271                                                   BugReport &BR) override;
00272 };
00273 
00274 /// \brief When a region containing undefined value or '0' value is passed 
00275 /// as an argument in a call, marks the call as interesting.
00276 ///
00277 /// As a result, BugReporter will not prune the path through the function even
00278 /// if the region's contents are not modified/accessed by the call.
00279 class UndefOrNullArgVisitor
00280   : public BugReporterVisitorImpl<UndefOrNullArgVisitor> {
00281 
00282   /// The interesting memory region this visitor is tracking.
00283   const MemRegion *R;
00284 
00285 public:
00286   UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
00287 
00288   void Profile(llvm::FoldingSetNodeID &ID) const override {
00289     static int Tag = 0;
00290     ID.AddPointer(&Tag);
00291     ID.AddPointer(R);
00292   }
00293 
00294   PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
00295                                  const ExplodedNode *PrevN,
00296                                  BugReporterContext &BRC,
00297                                  BugReport &BR) override;
00298 };
00299 
00300 class SuppressInlineDefensiveChecksVisitor
00301 : public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor>
00302 {
00303   /// The symbolic value for which we are tracking constraints.
00304   /// This value is constrained to null in the end of path.
00305   DefinedSVal V;
00306 
00307   /// Track if we found the node where the constraint was first added.
00308   bool IsSatisfied;
00309 
00310   /// Since the visitors can be registered on nodes previous to the last
00311   /// node in the BugReport, but the path traversal always starts with the last
00312   /// node, the visitor invariant (that we start with a node in which V is null)
00313   /// might not hold when node visitation starts. We are going to start tracking
00314   /// from the last node in which the value is null.
00315   bool IsTrackingTurnedOn;
00316 
00317 public:
00318   SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
00319 
00320   void Profile(llvm::FoldingSetNodeID &ID) const override;
00321 
00322   /// Return the tag associated with this visitor.  This tag will be used
00323   /// to make all PathDiagnosticPieces created by this visitor.
00324   static const char *getTag();
00325 
00326   PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
00327                                  const ExplodedNode *Pred,
00328                                  BugReporterContext &BRC,
00329                                  BugReport &BR) override;
00330 };
00331 
00332 namespace bugreporter {
00333 
00334 /// Attempts to add visitors to trace a null or undefined value back to its
00335 /// point of origin, whether it is a symbol constrained to null or an explicit
00336 /// assignment.
00337 ///
00338 /// \param N A node "downstream" from the evaluation of the statement.
00339 /// \param S The statement whose value is null or undefined.
00340 /// \param R The bug report to which visitors should be attached.
00341 /// \param IsArg Whether the statement is an argument to an inlined function.
00342 ///              If this is the case, \p N \em must be the CallEnter node for
00343 ///              the function.
00344 /// \param EnableNullFPSuppression Whether we should employ false positive
00345 ///         suppression (inlined defensive checks, returned null).
00346 ///
00347 /// \return Whether or not the function was able to add visitors for this
00348 ///         statement. Note that returning \c true does not actually imply
00349 ///         that any visitors were added.
00350 bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R,
00351                            bool IsArg = false,
00352                            bool EnableNullFPSuppression = true);
00353 
00354 const Expr *getDerefExpr(const Stmt *S);
00355 const Stmt *GetDenomExpr(const ExplodedNode *N);
00356 const Stmt *GetRetValExpr(const ExplodedNode *N);
00357 bool isDeclRefExprToReference(const Expr *E);
00358 
00359 
00360 } // end namespace clang
00361 } // end namespace ento
00362 } // end namespace bugreporter
00363 
00364 
00365 #endif