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