BugReporterVisitor.h revision 6bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89
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 21namespace clang { 22 23namespace ento { 24 25class BugReport; 26class BugReporterContext; 27class ExplodedNode; 28class MemRegion; 29class 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.) 38class BugReporterVisitor : public llvm::FoldingSetNode { 39public: 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.) 90template <class DERIVED> 91class BugReporterVisitorImpl : public BugReporterVisitor { 92 BugReporterVisitor *clone() const override { 93 return new DERIVED(*static_cast<const DERIVED *>(this)); 94 } 95}; 96 97class 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 108public: 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 override; 122 123 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 124 const ExplodedNode *PrevN, 125 BugReporterContext &BRC, 126 BugReport &BR) override; 127}; 128 129class 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 141public: 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 158private: 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. 166class NilReceiverBRVisitor 167 : public BugReporterVisitorImpl<NilReceiverBRVisitor> { 168public: 169 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. 186class ConditionBRVisitor : public BugReporterVisitorImpl<ConditionBRVisitor> { 187public: 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. 252class LikelyFalsePositiveSuppressionBRVisitor 253 : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> { 254public: 255 static void *getTag() { 256 static int Tag = 0; 257 return static_cast<void *>(&Tag); 258 } 259 260 void Profile(llvm::FoldingSetNodeID &ID) const override { 261 ID.AddPointer(getTag()); 262 } 263 264 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 265 const ExplodedNode *Prev, 266 BugReporterContext &BRC, 267 BugReport &BR) override { 268 return nullptr; 269 } 270 271 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. 281class UndefOrNullArgVisitor 282 : public BugReporterVisitorImpl<UndefOrNullArgVisitor> { 283 284 /// The interesting memory region this visitor is tracking. 285 const MemRegion *R; 286 287public: 288 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {} 289 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 302class 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 319public: 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 334namespace 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. 352bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, 353 bool IsArg = false, 354 bool EnableNullFPSuppression = true); 355 356const Expr *getDerefExpr(const Stmt *S); 357const Stmt *GetDenomExpr(const ExplodedNode *N); 358const Stmt *GetRetValExpr(const ExplodedNode *N); 359bool 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