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 class CFGBlock; 23 24 namespace ento { 25 26 class BugReport; 27 class BugReporterContext; 28 class ExplodedNode; 29 class MemRegion; 30 class PathDiagnosticPiece; 31 32 /// \brief BugReporterVisitors are used to add custom diagnostics along a path. 33 /// 34 /// Custom visitors should subclass the BugReporterVisitorImpl class for a 35 /// default implementation of the clone() method. 36 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the 37 /// default implementation of clone() will NOT do the right thing, and you 38 /// will have to provide your own implementation.) 39 class BugReporterVisitor : public llvm::FoldingSetNode { 40 public: 41 BugReporterVisitor() = default; 42 BugReporterVisitor(const BugReporterVisitor &) = default; BugReporterVisitor(BugReporterVisitor &&)43 BugReporterVisitor(BugReporterVisitor &&) {} 44 virtual ~BugReporterVisitor(); 45 46 /// \brief Returns a copy of this BugReporter. 47 /// 48 /// Custom BugReporterVisitors should not override this method directly. 49 /// Instead, they should inherit from BugReporterVisitorImpl and provide 50 /// a protected or public copy constructor. 51 /// 52 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the 53 /// default implementation of clone() will NOT do the right thing, and you 54 /// will have to provide your own implementation.) 55 virtual std::unique_ptr<BugReporterVisitor> clone() const = 0; 56 57 /// \brief Return a diagnostic piece which should be associated with the 58 /// given node. 59 /// 60 /// The last parameter can be used to register a new visitor with the given 61 /// BugReport while processing a node. 62 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ, 63 const ExplodedNode *Pred, 64 BugReporterContext &BRC, 65 BugReport &BR) = 0; 66 67 /// \brief Provide custom definition for the final diagnostic piece on the 68 /// path - the piece, which is displayed before the path is expanded. 69 /// 70 /// If returns NULL the default implementation will be used. 71 /// Also note that at most one visitor of a BugReport should generate a 72 /// non-NULL end of path diagnostic piece. 73 virtual std::unique_ptr<PathDiagnosticPiece> 74 getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR); 75 76 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0; 77 78 /// \brief Generates the default final diagnostic piece. 79 static std::unique_ptr<PathDiagnosticPiece> 80 getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N, 81 BugReport &BR); 82 }; 83 84 /// This class provides a convenience implementation for clone() using the 85 /// Curiously-Recurring Template Pattern. If you are implementing a custom 86 /// BugReporterVisitor, subclass BugReporterVisitorImpl and provide a public 87 /// or protected copy constructor. 88 /// 89 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the 90 /// default implementation of clone() will NOT do the right thing, and you 91 /// will have to provide your own implementation.) 92 template <class DERIVED> 93 class BugReporterVisitorImpl : public BugReporterVisitor { clone()94 std::unique_ptr<BugReporterVisitor> clone() const override { 95 return llvm::make_unique<DERIVED>(*static_cast<const DERIVED *>(this)); 96 } 97 }; 98 99 class FindLastStoreBRVisitor final 100 : public BugReporterVisitorImpl<FindLastStoreBRVisitor> { 101 const MemRegion *R; 102 SVal V; 103 bool Satisfied; 104 105 /// If the visitor is tracking the value directly responsible for the 106 /// bug, we are going to employ false positive suppression. 107 bool EnableNullFPSuppression; 108 109 public: 110 /// Creates a visitor for every VarDecl inside a Stmt and registers it with 111 /// the BugReport. 112 static void registerStatementVarDecls(BugReport &BR, const Stmt *S, 113 bool EnableNullFPSuppression); 114 FindLastStoreBRVisitor(KnownSVal V,const MemRegion * R,bool InEnableNullFPSuppression)115 FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R, 116 bool InEnableNullFPSuppression) 117 : R(R), 118 V(V), 119 Satisfied(false), 120 EnableNullFPSuppression(InEnableNullFPSuppression) {} 121 122 void Profile(llvm::FoldingSetNodeID &ID) const override; 123 124 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 125 const ExplodedNode *PrevN, 126 BugReporterContext &BRC, 127 BugReport &BR) override; 128 }; 129 130 class TrackConstraintBRVisitor final 131 : public BugReporterVisitorImpl<TrackConstraintBRVisitor> { 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: TrackConstraintBRVisitor(DefinedSVal constraint,bool assumption)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 override; 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) override; 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 final 167 : public BugReporterVisitorImpl<NilReceiverBRVisitor> { 168 public: 169 Profile(llvm::FoldingSetNodeID & ID)170 void Profile(llvm::FoldingSetNodeID &ID) const override { 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) override; 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 final 187 : public BugReporterVisitorImpl<ConditionBRVisitor> { 188 public: Profile(llvm::FoldingSetNodeID & ID)189 void Profile(llvm::FoldingSetNodeID &ID) const override { 190 static int x = 0; 191 ID.AddPointer(&x); 192 } 193 194 /// Return the tag associated with this visitor. This tag will be used 195 /// to make all PathDiagnosticPieces created by this visitor. 196 static const char *getTag(); 197 198 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 199 const ExplodedNode *Prev, 200 BugReporterContext &BRC, 201 BugReport &BR) override; 202 203 PathDiagnosticPiece *VisitNodeImpl(const ExplodedNode *N, 204 const ExplodedNode *Prev, 205 BugReporterContext &BRC, 206 BugReport &BR); 207 208 PathDiagnosticPiece *VisitTerminator(const Stmt *Term, 209 const ExplodedNode *N, 210 const CFGBlock *srcBlk, 211 const CFGBlock *dstBlk, 212 BugReport &R, 213 BugReporterContext &BRC); 214 215 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, 216 bool tookTrue, 217 BugReporterContext &BRC, 218 BugReport &R, 219 const ExplodedNode *N); 220 221 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, 222 const DeclRefExpr *DR, 223 const bool tookTrue, 224 BugReporterContext &BRC, 225 BugReport &R, 226 const ExplodedNode *N); 227 228 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, 229 const BinaryOperator *BExpr, 230 const bool tookTrue, 231 BugReporterContext &BRC, 232 BugReport &R, 233 const ExplodedNode *N); 234 235 PathDiagnosticPiece *VisitConditionVariable(StringRef LhsString, 236 const Expr *CondVarExpr, 237 const bool tookTrue, 238 BugReporterContext &BRC, 239 BugReport &R, 240 const ExplodedNode *N); 241 242 bool patternMatch(const Expr *Ex, 243 raw_ostream &Out, 244 BugReporterContext &BRC, 245 BugReport &R, 246 const ExplodedNode *N, 247 Optional<bool> &prunable); 248 }; 249 250 /// \brief Suppress reports that might lead to known false positives. 251 /// 252 /// Currently this suppresses reports based on locations of bugs. 253 class LikelyFalsePositiveSuppressionBRVisitor final 254 : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> { 255 public: getTag()256 static void *getTag() { 257 static int Tag = 0; 258 return static_cast<void *>(&Tag); 259 } 260 Profile(llvm::FoldingSetNodeID & ID)261 void Profile(llvm::FoldingSetNodeID &ID) const override { 262 ID.AddPointer(getTag()); 263 } 264 VisitNode(const ExplodedNode * N,const ExplodedNode * Prev,BugReporterContext & BRC,BugReport & BR)265 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 266 const ExplodedNode *Prev, 267 BugReporterContext &BRC, 268 BugReport &BR) override { 269 return nullptr; 270 } 271 272 std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC, 273 const ExplodedNode *N, 274 BugReport &BR) override; 275 }; 276 277 /// \brief When a region containing undefined value or '0' value is passed 278 /// as an argument in a call, marks the call as interesting. 279 /// 280 /// As a result, BugReporter will not prune the path through the function even 281 /// if the region's contents are not modified/accessed by the call. 282 class UndefOrNullArgVisitor final 283 : public BugReporterVisitorImpl<UndefOrNullArgVisitor> { 284 285 /// The interesting memory region this visitor is tracking. 286 const MemRegion *R; 287 288 public: UndefOrNullArgVisitor(const MemRegion * InR)289 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {} 290 Profile(llvm::FoldingSetNodeID & ID)291 void Profile(llvm::FoldingSetNodeID &ID) const override { 292 static int Tag = 0; 293 ID.AddPointer(&Tag); 294 ID.AddPointer(R); 295 } 296 297 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 298 const ExplodedNode *PrevN, 299 BugReporterContext &BRC, 300 BugReport &BR) override; 301 }; 302 303 class SuppressInlineDefensiveChecksVisitor final 304 : public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor> { 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 override; 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) override; 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 368