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 BugReporterVisitor() = default; 41 BugReporterVisitor(const BugReporterVisitor &) = default; BugReporterVisitor(BugReporterVisitor &&)42 BugReporterVisitor(BugReporterVisitor &&) {} 43 virtual ~BugReporterVisitor(); 44 45 /// \brief Returns a copy of this BugReporter. 46 /// 47 /// Custom BugReporterVisitors should not override this method directly. 48 /// Instead, they should inherit from BugReporterVisitorImpl and provide 49 /// a protected or public copy constructor. 50 /// 51 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the 52 /// default implementation of clone() will NOT do the right thing, and you 53 /// will have to provide your own implementation.) 54 virtual std::unique_ptr<BugReporterVisitor> clone() const = 0; 55 56 /// \brief Return a diagnostic piece which should be associated with the 57 /// given node. 58 /// 59 /// The last parameter can be used to register a new visitor with the given 60 /// BugReport while processing a node. 61 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ, 62 const ExplodedNode *Pred, 63 BugReporterContext &BRC, 64 BugReport &BR) = 0; 65 66 /// \brief Provide custom definition for the final diagnostic piece on the 67 /// path - the piece, which is displayed before the path is expanded. 68 /// 69 /// If returns NULL the default implementation will be used. 70 /// Also note that at most one visitor of a BugReport should generate a 71 /// non-NULL end of path diagnostic piece. 72 virtual std::unique_ptr<PathDiagnosticPiece> 73 getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR); 74 75 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0; 76 77 /// \brief Generates the default final diagnostic piece. 78 static std::unique_ptr<PathDiagnosticPiece> 79 getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N, 80 BugReport &BR); 81 }; 82 83 /// This class provides a convenience implementation for clone() using the 84 /// Curiously-Recurring Template Pattern. If you are implementing a custom 85 /// BugReporterVisitor, subclass BugReporterVisitorImpl and provide a public 86 /// or protected copy constructor. 87 /// 88 /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the 89 /// default implementation of clone() will NOT do the right thing, and you 90 /// will have to provide your own implementation.) 91 template <class DERIVED> 92 class BugReporterVisitorImpl : public BugReporterVisitor { clone()93 std::unique_ptr<BugReporterVisitor> clone() const override { 94 return llvm::make_unique<DERIVED>(*static_cast<const DERIVED *>(this)); 95 } 96 }; 97 98 class FindLastStoreBRVisitor final 99 : public BugReporterVisitorImpl<FindLastStoreBRVisitor> { 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 FindLastStoreBRVisitor(KnownSVal V,const MemRegion * R,bool InEnableNullFPSuppression)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 override; 122 123 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 124 const ExplodedNode *PrevN, 125 BugReporterContext &BRC, 126 BugReport &BR) override; 127 }; 128 129 class TrackConstraintBRVisitor final 130 : public BugReporterVisitorImpl<TrackConstraintBRVisitor> { 131 DefinedSVal Constraint; 132 bool Assumption; 133 bool IsSatisfied; 134 bool IsZeroCheck; 135 136 /// We should start tracking from the last node along the path in which the 137 /// value is constrained. 138 bool IsTrackingTurnedOn; 139 140 public: TrackConstraintBRVisitor(DefinedSVal constraint,bool assumption)141 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) 142 : Constraint(constraint), Assumption(assumption), IsSatisfied(false), 143 IsZeroCheck(!Assumption && Constraint.getAs<Loc>()), 144 IsTrackingTurnedOn(false) {} 145 146 void Profile(llvm::FoldingSetNodeID &ID) const override; 147 148 /// Return the tag associated with this visitor. This tag will be used 149 /// to make all PathDiagnosticPieces created by this visitor. 150 static const char *getTag(); 151 152 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 153 const ExplodedNode *PrevN, 154 BugReporterContext &BRC, 155 BugReport &BR) override; 156 157 private: 158 /// Checks if the constraint is valid in the current state. 159 bool isUnderconstrained(const ExplodedNode *N) const; 160 161 }; 162 163 /// \class NilReceiverBRVisitor 164 /// \brief Prints path notes when a message is sent to a nil receiver. 165 class NilReceiverBRVisitor final 166 : public BugReporterVisitorImpl<NilReceiverBRVisitor> { 167 public: 168 Profile(llvm::FoldingSetNodeID & ID)169 void Profile(llvm::FoldingSetNodeID &ID) const override { 170 static int x = 0; 171 ID.AddPointer(&x); 172 } 173 174 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 175 const ExplodedNode *PrevN, 176 BugReporterContext &BRC, 177 BugReport &BR) override; 178 179 /// If the statement is a message send expression with nil receiver, returns 180 /// the receiver expression. Returns NULL otherwise. 181 static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N); 182 }; 183 184 /// Visitor that tries to report interesting diagnostics from conditions. 185 class ConditionBRVisitor final 186 : public BugReporterVisitorImpl<ConditionBRVisitor> { 187 public: Profile(llvm::FoldingSetNodeID & ID)188 void Profile(llvm::FoldingSetNodeID &ID) const override { 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 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 198 const ExplodedNode *Prev, 199 BugReporterContext &BRC, 200 BugReport &BR) override; 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 final 253 : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> { 254 public: getTag()255 static void *getTag() { 256 static int Tag = 0; 257 return static_cast<void *>(&Tag); 258 } 259 Profile(llvm::FoldingSetNodeID & ID)260 void Profile(llvm::FoldingSetNodeID &ID) const override { 261 ID.AddPointer(getTag()); 262 } 263 VisitNode(const ExplodedNode * N,const ExplodedNode * Prev,BugReporterContext & BRC,BugReport & BR)264 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 265 const ExplodedNode *Prev, 266 BugReporterContext &BRC, 267 BugReport &BR) override { 268 return nullptr; 269 } 270 271 std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC, 272 const ExplodedNode *N, 273 BugReport &BR) override; 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 final 282 : public BugReporterVisitorImpl<UndefOrNullArgVisitor> { 283 284 /// The interesting memory region this visitor is tracking. 285 const MemRegion *R; 286 287 public: UndefOrNullArgVisitor(const MemRegion * InR)288 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {} 289 Profile(llvm::FoldingSetNodeID & ID)290 void Profile(llvm::FoldingSetNodeID &ID) const override { 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) override; 300 }; 301 302 class SuppressInlineDefensiveChecksVisitor final 303 : public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor> { 304 /// The symbolic value for which we are tracking constraints. 305 /// This value is constrained to null in the end of path. 306 DefinedSVal V; 307 308 /// Track if we found the node where the constraint was first added. 309 bool IsSatisfied; 310 311 /// Since the visitors can be registered on nodes previous to the last 312 /// node in the BugReport, but the path traversal always starts with the last 313 /// node, the visitor invariant (that we start with a node in which V is null) 314 /// might not hold when node visitation starts. We are going to start tracking 315 /// from the last node in which the value is null. 316 bool IsTrackingTurnedOn; 317 318 public: 319 SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N); 320 321 void Profile(llvm::FoldingSetNodeID &ID) const override; 322 323 /// Return the tag associated with this visitor. This tag will be used 324 /// to make all PathDiagnosticPieces created by this visitor. 325 static const char *getTag(); 326 327 PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ, 328 const ExplodedNode *Pred, 329 BugReporterContext &BRC, 330 BugReport &BR) override; 331 }; 332 333 namespace bugreporter { 334 335 /// Attempts to add visitors to trace a null or undefined value back to its 336 /// point of origin, whether it is a symbol constrained to null or an explicit 337 /// assignment. 338 /// 339 /// \param N A node "downstream" from the evaluation of the statement. 340 /// \param S The statement whose value is null or undefined. 341 /// \param R The bug report to which visitors should be attached. 342 /// \param IsArg Whether the statement is an argument to an inlined function. 343 /// If this is the case, \p N \em must be the CallEnter node for 344 /// the function. 345 /// \param EnableNullFPSuppression Whether we should employ false positive 346 /// suppression (inlined defensive checks, returned null). 347 /// 348 /// \return Whether or not the function was able to add visitors for this 349 /// statement. Note that returning \c true does not actually imply 350 /// that any visitors were added. 351 bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, 352 bool IsArg = false, 353 bool EnableNullFPSuppression = true); 354 355 const Expr *getDerefExpr(const Stmt *S); 356 const Stmt *GetDenomExpr(const ExplodedNode *N); 357 const Stmt *GetRetValExpr(const ExplodedNode *N); 358 bool isDeclRefExprToReference(const Expr *E); 359 360 361 } // end namespace clang 362 } // end namespace ento 363 } // end namespace bugreporter 364 365 366 #endif 367