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