BugReporterVisitor.h revision cfa88f893915ceb8ae4ce2f17c46c24a4d67502f
1//===--- BugReporterVisitor.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 declares BugReporterVisitors, which are used to generate enhanced 11// diagnostic traces. 12// 13//===----------------------------------------------------------------------===// 14 15#ifndef LLVM_CLANG_GR_BUGREPORTERVISITOR 16#define LLVM_CLANG_GR_BUGREPORTERVISITOR 17 18#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 19#include "llvm/ADT/FoldingSet.h" 20 21namespace clang { 22 23namespace ento { 24 25class BugReport; 26class BugReporterContext; 27class ExplodedNode; 28class MemRegion; 29class PathDiagnosticPiece; 30 31/// \brief BugReporterVisitors are used to add custom diagnostics along a path. 32/// 33/// Custom visitors should subclass the BugReporterVisitorImpl class for a 34/// default implementation of the clone() method. 35/// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the 36/// default implementation of clone() will NOT do the right thing, and you 37/// will have to provide your own implementation.) 38class BugReporterVisitor : public llvm::FoldingSetNode { 39public: 40 virtual ~BugReporterVisitor(); 41 42 /// \brief Returns a copy of this BugReporter. 43 /// 44 /// Custom BugReporterVisitors should not override this method directly. 45 /// Instead, they should inherit from BugReporterVisitorImpl and provide 46 /// a protected or public copy constructor. 47 /// 48 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the 49 /// default implementation of clone() will NOT do the right thing, and you 50 /// will have to provide your own implementation.) 51 virtual BugReporterVisitor *clone() const = 0; 52 53 /// \brief Return a diagnostic piece which should be associated with the 54 /// given node. 55 /// 56 /// The last parameter can be used to register a new visitor with the given 57 /// BugReport while processing a node. 58 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 59 const ExplodedNode *PrevN, 60 BugReporterContext &BRC, 61 BugReport &BR) = 0; 62 63 /// \brief Provide custom definition for the final diagnostic piece on the 64 /// path - the piece, which is displayed before the path is expanded. 65 /// 66 /// If returns NULL the default implementation will be used. 67 /// Also note that at most one visitor of a BugReport should generate a 68 /// non-NULL end of path diagnostic piece. 69 virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, 70 const ExplodedNode *N, 71 BugReport &BR); 72 73 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0; 74 75 /// \brief Generates the default final diagnostic piece. 76 static PathDiagnosticPiece *getDefaultEndPath(BugReporterContext &BRC, 77 const ExplodedNode *N, 78 BugReport &BR); 79 80}; 81 82/// This class provides a convenience implementation for clone() using the 83/// Curiously-Recurring Template Pattern. If you are implementing a custom 84/// BugReporterVisitor, subclass BugReporterVisitorImpl and provide a public 85/// or protected copy constructor. 86/// 87/// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the 88/// default implementation of clone() will NOT do the right thing, and you 89/// will have to provide your own implementation.) 90template <class DERIVED> 91class BugReporterVisitorImpl : public BugReporterVisitor { 92 virtual BugReporterVisitor *clone() const { 93 return new DERIVED(*static_cast<const DERIVED *>(this)); 94 } 95}; 96 97class FindLastStoreBRVisitor 98 : public BugReporterVisitorImpl<FindLastStoreBRVisitor> 99{ 100 const MemRegion *R; 101 SVal V; 102 bool satisfied; 103 104public: 105 /// \brief Convenience method to create a visitor given only the MemRegion. 106 /// Returns NULL if the visitor cannot be created. For example, when the 107 /// corresponding value is unknown. 108 static BugReporterVisitor *createVisitorObject(const ExplodedNode *N, 109 const MemRegion *R); 110 111 /// Creates a visitor for every VarDecl inside a Stmt and registers it with 112 /// the BugReport. 113 static void registerStatementVarDecls(BugReport &BR, const Stmt *S); 114 115 FindLastStoreBRVisitor(SVal v, const MemRegion *r) 116 : R(r), V(v), satisfied(false) { 117 assert (!V.isUnknown() && "Cannot track unknown value."); 118 119 // TODO: Does it make sense to allow undef values here? 120 // (If not, also see UndefCapturedBlockVarChecker)? 121 } 122 123 void Profile(llvm::FoldingSetNodeID &ID) const; 124 125 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 126 const ExplodedNode *PrevN, 127 BugReporterContext &BRC, 128 BugReport &BR); 129}; 130 131class TrackConstraintBRVisitor 132 : public BugReporterVisitorImpl<TrackConstraintBRVisitor> 133{ 134 DefinedSVal Constraint; 135 const bool Assumption; 136 bool isSatisfied; 137 138public: 139 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) 140 : Constraint(constraint), Assumption(assumption), isSatisfied(false) {} 141 142 void Profile(llvm::FoldingSetNodeID &ID) const; 143 144 /// Return the tag associated with this visitor. This tag will be used 145 /// to make all PathDiagnosticPieces created by this visitor. 146 static const char *getTag(); 147 148 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 149 const ExplodedNode *PrevN, 150 BugReporterContext &BRC, 151 BugReport &BR); 152}; 153 154class NilReceiverBRVisitor 155 : public BugReporterVisitorImpl<NilReceiverBRVisitor> 156{ 157public: 158 void Profile(llvm::FoldingSetNodeID &ID) const { 159 static int x = 0; 160 ID.AddPointer(&x); 161 } 162 163 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 164 const ExplodedNode *PrevN, 165 BugReporterContext &BRC, 166 BugReport &BR); 167}; 168 169/// Visitor that tries to report interesting diagnostics from conditions. 170class ConditionBRVisitor : public BugReporterVisitorImpl<ConditionBRVisitor> { 171public: 172 void Profile(llvm::FoldingSetNodeID &ID) const { 173 static int x = 0; 174 ID.AddPointer(&x); 175 } 176 177 /// Return the tag associated with this visitor. This tag will be used 178 /// to make all PathDiagnosticPieces created by this visitor. 179 static const char *getTag(); 180 181 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 182 const ExplodedNode *Prev, 183 BugReporterContext &BRC, 184 BugReport &BR); 185 186 PathDiagnosticPiece *VisitNodeImpl(const ExplodedNode *N, 187 const ExplodedNode *Prev, 188 BugReporterContext &BRC, 189 BugReport &BR); 190 191 PathDiagnosticPiece *VisitTerminator(const Stmt *Term, 192 const ExplodedNode *N, 193 const CFGBlock *srcBlk, 194 const CFGBlock *dstBlk, 195 BugReport &R, 196 BugReporterContext &BRC); 197 198 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, 199 bool tookTrue, 200 BugReporterContext &BRC, 201 BugReport &R, 202 const ExplodedNode *N); 203 204 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, 205 const DeclRefExpr *DR, 206 const bool tookTrue, 207 BugReporterContext &BRC, 208 BugReport &R, 209 const ExplodedNode *N); 210 211 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, 212 const BinaryOperator *BExpr, 213 const bool tookTrue, 214 BugReporterContext &BRC, 215 BugReport &R, 216 const ExplodedNode *N); 217 218 PathDiagnosticPiece *VisitConditionVariable(StringRef LhsString, 219 const Expr *CondVarExpr, 220 const bool tookTrue, 221 BugReporterContext &BRC, 222 BugReport &R, 223 const ExplodedNode *N); 224 225 bool patternMatch(const Expr *Ex, 226 raw_ostream &Out, 227 BugReporterContext &BRC, 228 BugReport &R, 229 const ExplodedNode *N, 230 llvm::Optional<bool> &prunable); 231}; 232 233/// \brief When a region containing undefined value or '0' value is passed 234/// as an argument in a call, marks the call as interesting. 235/// 236/// As a result, BugReporter will not prune the path through the function even 237/// if the region's contents are not modified/accessed by the call. 238class UndefOrNullArgVisitor 239 : public BugReporterVisitorImpl<UndefOrNullArgVisitor> { 240 241 /// The interesting memory region this visitor is tracking. 242 const MemRegion *R; 243 244public: 245 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {} 246 247 virtual void Profile(llvm::FoldingSetNodeID &ID) const { 248 static int Tag = 0; 249 ID.AddPointer(&Tag); 250 ID.AddPointer(R); 251 } 252 253 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 254 const ExplodedNode *PrevN, 255 BugReporterContext &BRC, 256 BugReport &BR); 257}; 258 259namespace bugreporter { 260 261/// Attempts to add visitors to trace a null or undefined value back to its 262/// point of origin, whether it is a symbol constrained to null or an explicit 263/// assignment. 264/// 265/// \param N A node "downstream" from the evaluation of the statement. 266/// \param S The statement whose value is null or undefined. 267/// \param R The bug report to which visitors should be attached. 268/// \param IsArg Whether the statement is an argument to an inlined function. 269/// If this is the case, \p N \em must be the CallEnter node for 270/// the function. 271/// 272/// \return Whether or not the function was able to add visitors for this 273/// statement. Note that returning \c true does not actually imply 274/// that any visitors were added. 275bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, 276 bool IsArg = false); 277 278const Stmt *GetDerefExpr(const ExplodedNode *N); 279const Stmt *GetDenomExpr(const ExplodedNode *N); 280const Stmt *GetRetValExpr(const ExplodedNode *N); 281bool isDeclRefExprToReference(const Expr *E); 282 283 284} // end namespace clang 285} // end namespace ento 286} // end namespace bugreporter 287 288 289#endif //LLVM_CLANG_GR__BUGREPORTERVISITOR 290