BugReporterVisitor.h revision 85a92cfa52ddf4c45fe2baca4d7fea0bdc5ed103
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 *Succ, 59 const ExplodedNode *Pred, 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(KnownSVal V, const MemRegion *R) 116 : R(R), 117 V(V), 118 Satisfied(false) {} 119 120 void Profile(llvm::FoldingSetNodeID &ID) const; 121 122 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 123 const ExplodedNode *PrevN, 124 BugReporterContext &BRC, 125 BugReport &BR); 126}; 127 128class TrackConstraintBRVisitor 129 : public BugReporterVisitorImpl<TrackConstraintBRVisitor> 130{ 131 DefinedSVal Constraint; 132 bool Assumption; 133 bool IsSatisfied; 134 bool IsZeroCheck; 135 136public: 137 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) 138 : Constraint(constraint), Assumption(assumption), IsSatisfied(false), 139 IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {} 140 141 void Profile(llvm::FoldingSetNodeID &ID) const; 142 143 /// Return the tag associated with this visitor. This tag will be used 144 /// to make all PathDiagnosticPieces created by this visitor. 145 static const char *getTag(); 146 147 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 148 const ExplodedNode *PrevN, 149 BugReporterContext &BRC, 150 BugReport &BR); 151 152private: 153 /// Checks if the constraint is valid in the current state. 154 bool isUnderconstrained(const ExplodedNode *N) const; 155 156}; 157 158class NilReceiverBRVisitor 159 : public BugReporterVisitorImpl<NilReceiverBRVisitor> 160{ 161public: 162 void Profile(llvm::FoldingSetNodeID &ID) const { 163 static int x = 0; 164 ID.AddPointer(&x); 165 } 166 167 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 168 const ExplodedNode *PrevN, 169 BugReporterContext &BRC, 170 BugReport &BR); 171}; 172 173/// Visitor that tries to report interesting diagnostics from conditions. 174class ConditionBRVisitor : public BugReporterVisitorImpl<ConditionBRVisitor> { 175public: 176 void Profile(llvm::FoldingSetNodeID &ID) const { 177 static int x = 0; 178 ID.AddPointer(&x); 179 } 180 181 /// Return the tag associated with this visitor. This tag will be used 182 /// to make all PathDiagnosticPieces created by this visitor. 183 static const char *getTag(); 184 185 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 186 const ExplodedNode *Prev, 187 BugReporterContext &BRC, 188 BugReport &BR); 189 190 PathDiagnosticPiece *VisitNodeImpl(const ExplodedNode *N, 191 const ExplodedNode *Prev, 192 BugReporterContext &BRC, 193 BugReport &BR); 194 195 PathDiagnosticPiece *VisitTerminator(const Stmt *Term, 196 const ExplodedNode *N, 197 const CFGBlock *srcBlk, 198 const CFGBlock *dstBlk, 199 BugReport &R, 200 BugReporterContext &BRC); 201 202 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, 203 bool tookTrue, 204 BugReporterContext &BRC, 205 BugReport &R, 206 const ExplodedNode *N); 207 208 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, 209 const DeclRefExpr *DR, 210 const bool tookTrue, 211 BugReporterContext &BRC, 212 BugReport &R, 213 const ExplodedNode *N); 214 215 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, 216 const BinaryOperator *BExpr, 217 const bool tookTrue, 218 BugReporterContext &BRC, 219 BugReport &R, 220 const ExplodedNode *N); 221 222 PathDiagnosticPiece *VisitConditionVariable(StringRef LhsString, 223 const Expr *CondVarExpr, 224 const bool tookTrue, 225 BugReporterContext &BRC, 226 BugReport &R, 227 const ExplodedNode *N); 228 229 bool patternMatch(const Expr *Ex, 230 raw_ostream &Out, 231 BugReporterContext &BRC, 232 BugReport &R, 233 const ExplodedNode *N, 234 Optional<bool> &prunable); 235}; 236 237/// \brief Suppress reports that might lead to known false positives. 238/// 239/// Currently this suppresses reports based on locations of bugs. 240class LikelyFalsePositiveSuppressionBRVisitor 241 : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> { 242public: 243 static void *getTag() { 244 static int Tag = 0; 245 return static_cast<void *>(&Tag); 246 } 247 248 void Profile(llvm::FoldingSetNodeID &ID) const { 249 ID.AddPointer(getTag()); 250 } 251 252 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 253 const ExplodedNode *Prev, 254 BugReporterContext &BRC, 255 BugReport &BR) { 256 return 0; 257 } 258 259 virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, 260 const ExplodedNode *N, 261 BugReport &BR); 262}; 263 264/// \brief When a region containing undefined value or '0' value is passed 265/// as an argument in a call, marks the call as interesting. 266/// 267/// As a result, BugReporter will not prune the path through the function even 268/// if the region's contents are not modified/accessed by the call. 269class UndefOrNullArgVisitor 270 : public BugReporterVisitorImpl<UndefOrNullArgVisitor> { 271 272 /// The interesting memory region this visitor is tracking. 273 const MemRegion *R; 274 275public: 276 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {} 277 278 virtual void Profile(llvm::FoldingSetNodeID &ID) const { 279 static int Tag = 0; 280 ID.AddPointer(&Tag); 281 ID.AddPointer(R); 282 } 283 284 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 285 const ExplodedNode *PrevN, 286 BugReporterContext &BRC, 287 BugReport &BR); 288}; 289 290class SuppressInlineDefensiveChecksVisitor 291: public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor> 292{ 293 /// The symbolic value for which we are tracking constraints. 294 /// This value is constrained to null in the end of path. 295 DefinedSVal V; 296 297 /// Track if we found the node where the constraint was first added. 298 bool IsSatisfied; 299 300 /// Since the visitors can be registered on nodes previous to the last 301 /// node in the BugReport, but the path traversal always starts with the last 302 /// node, the visitor invariant (that we start with a node in which V is null) 303 /// might not hold when node visitation starts. We are going to start tracking 304 /// from the last node in which the value is null. 305 bool IsTrackingTurnedOn; 306 307public: 308 SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N); 309 310 void Profile(llvm::FoldingSetNodeID &ID) const; 311 312 /// Return the tag associated with this visitor. This tag will be used 313 /// to make all PathDiagnosticPieces created by this visitor. 314 static const char *getTag(); 315 316 PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ, 317 const ExplodedNode *Pred, 318 BugReporterContext &BRC, 319 BugReport &BR); 320}; 321 322namespace bugreporter { 323 324/// Attempts to add visitors to trace a null or undefined value back to its 325/// point of origin, whether it is a symbol constrained to null or an explicit 326/// assignment. 327/// 328/// \param N A node "downstream" from the evaluation of the statement. 329/// \param S The statement whose value is null or undefined. 330/// \param R The bug report to which visitors should be attached. 331/// \param IsArg Whether the statement is an argument to an inlined function. 332/// If this is the case, \p N \em must be the CallEnter node for 333/// the function. 334/// 335/// \return Whether or not the function was able to add visitors for this 336/// statement. Note that returning \c true does not actually imply 337/// that any visitors were added. 338bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, 339 bool IsArg = false); 340 341const Expr *getDerefExpr(const Stmt *S); 342const Stmt *GetDenomExpr(const ExplodedNode *N); 343const Stmt *GetRetValExpr(const ExplodedNode *N); 344bool isDeclRefExprToReference(const Expr *E); 345 346 347} // end namespace clang 348} // end namespace ento 349} // end namespace bugreporter 350 351 352#endif //LLVM_CLANG_GR__BUGREPORTERVISITOR 353