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