1 //===- BugReporterVisitors.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_BUGREPORTERVISITORS_H 16 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H 17 18 #include "clang/Basic/LLVM.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h" 20 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 21 #include "llvm/ADT/FoldingSet.h" 22 #include "llvm/ADT/STLExtras.h" 23 #include "llvm/ADT/StringRef.h" 24 #include <memory> 25 26 namespace clang { 27 28 class BinaryOperator; 29 class CFGBlock; 30 class DeclRefExpr; 31 class Expr; 32 class Stmt; 33 34 namespace ento { 35 36 class BugReport; 37 class BugReporterContext; 38 class ExplodedNode; 39 class MemRegion; 40 class PathDiagnosticPiece; 41 42 /// BugReporterVisitors are used to add custom diagnostics along a path. 43 class BugReporterVisitor : public llvm::FoldingSetNode { 44 public: 45 BugReporterVisitor() = default; 46 BugReporterVisitor(const BugReporterVisitor &) = default; BugReporterVisitor(BugReporterVisitor &&)47 BugReporterVisitor(BugReporterVisitor &&) {} 48 virtual ~BugReporterVisitor(); 49 50 /// Return a diagnostic piece which should be associated with the 51 /// given node. 52 /// Note that this function does *not* get run on the very last node 53 /// of the report, as the PathDiagnosticPiece associated with the 54 /// last node should be unique. 55 /// Use {@code getEndPath} to customize the note associated with the report 56 /// end instead. 57 /// 58 /// The last parameter can be used to register a new visitor with the given 59 /// BugReport while processing a node. 60 virtual std::shared_ptr<PathDiagnosticPiece> 61 VisitNode(const ExplodedNode *Succ, 62 BugReporterContext &BRC, BugReport &BR) = 0; 63 64 /// Last function called on the visitor, no further calls to VisitNode 65 /// would follow. 66 virtual void finalizeVisitor(BugReporterContext &BRC, 67 const ExplodedNode *EndPathNode, 68 BugReport &BR); 69 70 /// Provide custom definition for the final diagnostic piece on the 71 /// path - the piece, which is displayed before the path is expanded. 72 /// 73 /// NOTE that this function can be implemented on at most one used visitor, 74 /// and otherwise it crahes at runtime. 75 virtual std::shared_ptr<PathDiagnosticPiece> 76 getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR); 77 78 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0; 79 80 /// Generates the default final diagnostic piece. 81 static std::shared_ptr<PathDiagnosticPiece> 82 getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N, 83 BugReport &BR); 84 }; 85 86 /// Finds last store into the given region, 87 /// which is different from a given symbolic value. 88 class FindLastStoreBRVisitor final : public BugReporterVisitor { 89 const MemRegion *R; 90 SVal V; 91 bool Satisfied = false; 92 93 /// If the visitor is tracking the value directly responsible for the 94 /// bug, we are going to employ false positive suppression. 95 bool EnableNullFPSuppression; 96 97 public: 98 /// Creates a visitor for every VarDecl inside a Stmt and registers it with 99 /// the BugReport. 100 static void registerStatementVarDecls(BugReport &BR, const Stmt *S, 101 bool EnableNullFPSuppression); 102 FindLastStoreBRVisitor(KnownSVal V,const MemRegion * R,bool InEnableNullFPSuppression)103 FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R, 104 bool InEnableNullFPSuppression) 105 : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression) {} 106 107 void Profile(llvm::FoldingSetNodeID &ID) const override; 108 109 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, 110 BugReporterContext &BRC, 111 BugReport &BR) override; 112 }; 113 114 class TrackConstraintBRVisitor final : public BugReporterVisitor { 115 DefinedSVal Constraint; 116 bool Assumption; 117 bool IsSatisfied = false; 118 bool IsZeroCheck; 119 120 /// We should start tracking from the last node along the path in which the 121 /// value is constrained. 122 bool IsTrackingTurnedOn = false; 123 124 public: TrackConstraintBRVisitor(DefinedSVal constraint,bool assumption)125 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) 126 : Constraint(constraint), Assumption(assumption), 127 IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {} 128 129 void Profile(llvm::FoldingSetNodeID &ID) const override; 130 131 /// Return the tag associated with this visitor. This tag will be used 132 /// to make all PathDiagnosticPieces created by this visitor. 133 static const char *getTag(); 134 135 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, 136 BugReporterContext &BRC, 137 BugReport &BR) override; 138 139 private: 140 /// Checks if the constraint is valid in the current state. 141 bool isUnderconstrained(const ExplodedNode *N) const; 142 }; 143 144 /// \class NilReceiverBRVisitor 145 /// Prints path notes when a message is sent to a nil receiver. 146 class NilReceiverBRVisitor final : public BugReporterVisitor { 147 public: Profile(llvm::FoldingSetNodeID & ID)148 void Profile(llvm::FoldingSetNodeID &ID) const override { 149 static int x = 0; 150 ID.AddPointer(&x); 151 } 152 153 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, 154 BugReporterContext &BRC, 155 BugReport &BR) override; 156 157 /// If the statement is a message send expression with nil receiver, returns 158 /// the receiver expression. Returns NULL otherwise. 159 static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N); 160 }; 161 162 /// Visitor that tries to report interesting diagnostics from conditions. 163 class ConditionBRVisitor final : public BugReporterVisitor { 164 // FIXME: constexpr initialization isn't supported by MSVC2013. 165 static const char *const GenericTrueMessage; 166 static const char *const GenericFalseMessage; 167 168 public: Profile(llvm::FoldingSetNodeID & ID)169 void Profile(llvm::FoldingSetNodeID &ID) const override { 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 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, 179 BugReporterContext &BRC, 180 BugReport &BR) override; 181 182 std::shared_ptr<PathDiagnosticPiece> VisitNodeImpl(const ExplodedNode *N, 183 BugReporterContext &BRC, 184 BugReport &BR); 185 186 std::shared_ptr<PathDiagnosticPiece> 187 VisitTerminator(const Stmt *Term, const ExplodedNode *N, 188 const CFGBlock *srcBlk, const CFGBlock *dstBlk, BugReport &R, 189 BugReporterContext &BRC); 190 191 std::shared_ptr<PathDiagnosticPiece> 192 VisitTrueTest(const Expr *Cond, bool tookTrue, BugReporterContext &BRC, 193 BugReport &R, const ExplodedNode *N); 194 195 std::shared_ptr<PathDiagnosticPiece> 196 VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue, 197 BugReporterContext &BRC, BugReport &R, const ExplodedNode *N); 198 199 std::shared_ptr<PathDiagnosticPiece> 200 VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr, 201 const bool tookTrue, BugReporterContext &BRC, BugReport &R, 202 const ExplodedNode *N); 203 204 std::shared_ptr<PathDiagnosticPiece> 205 VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, 206 const bool tookTrue, BugReporterContext &BRC, 207 BugReport &R, const ExplodedNode *N); 208 209 bool patternMatch(const Expr *Ex, 210 const Expr *ParentEx, 211 raw_ostream &Out, 212 BugReporterContext &BRC, 213 BugReport &R, 214 const ExplodedNode *N, 215 Optional<bool> &prunable); 216 217 static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece); 218 }; 219 220 /// Suppress reports that might lead to known false positives. 221 /// 222 /// Currently this suppresses reports based on locations of bugs. 223 class LikelyFalsePositiveSuppressionBRVisitor final 224 : public BugReporterVisitor { 225 public: getTag()226 static void *getTag() { 227 static int Tag = 0; 228 return static_cast<void *>(&Tag); 229 } 230 Profile(llvm::FoldingSetNodeID & ID)231 void Profile(llvm::FoldingSetNodeID &ID) const override { 232 ID.AddPointer(getTag()); 233 } 234 VisitNode(const ExplodedNode *,BugReporterContext &,BugReport &)235 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *, 236 BugReporterContext &, 237 BugReport &) override { 238 return nullptr; 239 } 240 241 void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N, 242 BugReport &BR) override; 243 }; 244 245 /// When a region containing undefined value or '0' value is passed 246 /// as an argument in a call, marks the call as interesting. 247 /// 248 /// As a result, BugReporter will not prune the path through the function even 249 /// if the region's contents are not modified/accessed by the call. 250 class UndefOrNullArgVisitor final : public BugReporterVisitor { 251 /// The interesting memory region this visitor is tracking. 252 const MemRegion *R; 253 254 public: UndefOrNullArgVisitor(const MemRegion * InR)255 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {} 256 Profile(llvm::FoldingSetNodeID & ID)257 void Profile(llvm::FoldingSetNodeID &ID) const override { 258 static int Tag = 0; 259 ID.AddPointer(&Tag); 260 ID.AddPointer(R); 261 } 262 263 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, 264 BugReporterContext &BRC, 265 BugReport &BR) override; 266 }; 267 268 class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor { 269 /// The symbolic value for which we are tracking constraints. 270 /// This value is constrained to null in the end of path. 271 DefinedSVal V; 272 273 /// Track if we found the node where the constraint was first added. 274 bool IsSatisfied = false; 275 276 /// Since the visitors can be registered on nodes previous to the last 277 /// node in the BugReport, but the path traversal always starts with the last 278 /// node, the visitor invariant (that we start with a node in which V is null) 279 /// might not hold when node visitation starts. We are going to start tracking 280 /// from the last node in which the value is null. 281 bool IsTrackingTurnedOn = false; 282 283 public: 284 SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N); 285 286 void Profile(llvm::FoldingSetNodeID &ID) const override; 287 288 /// Return the tag associated with this visitor. This tag will be used 289 /// to make all PathDiagnosticPieces created by this visitor. 290 static const char *getTag(); 291 292 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ, 293 BugReporterContext &BRC, 294 BugReport &BR) override; 295 }; 296 297 class CXXSelfAssignmentBRVisitor final : public BugReporterVisitor { 298 bool Satisfied = false; 299 300 public: 301 CXXSelfAssignmentBRVisitor() = default; 302 Profile(llvm::FoldingSetNodeID & ID)303 void Profile(llvm::FoldingSetNodeID &ID) const override {} 304 305 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ, 306 BugReporterContext &BRC, 307 BugReport &BR) override; 308 }; 309 310 /// The bug visitor prints a diagnostic message at the location where a given 311 /// variable was tainted. 312 class TaintBugVisitor final : public BugReporterVisitor { 313 private: 314 const SVal V; 315 316 public: TaintBugVisitor(const SVal V)317 TaintBugVisitor(const SVal V) : V(V) {} Profile(llvm::FoldingSetNodeID & ID)318 void Profile(llvm::FoldingSetNodeID &ID) const override { ID.Add(V); } 319 320 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, 321 BugReporterContext &BRC, 322 BugReport &BR) override; 323 }; 324 325 /// The bug visitor will walk all the nodes in a path and collect all the 326 /// constraints. When it reaches the root node, will create a refutation 327 /// manager and check if the constraints are satisfiable 328 class FalsePositiveRefutationBRVisitor final : public BugReporterVisitor { 329 private: 330 /// Holds the constraints in a given path 331 ConstraintRangeTy Constraints; 332 333 public: 334 FalsePositiveRefutationBRVisitor(); 335 336 void Profile(llvm::FoldingSetNodeID &ID) const override; 337 338 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, 339 BugReporterContext &BRC, 340 BugReport &BR) override; 341 342 void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode, 343 BugReport &BR) override; 344 }; 345 346 namespace bugreporter { 347 348 /// Attempts to add visitors to track expression value back to its point of 349 /// origin. 350 /// 351 /// \param N A node "downstream" from the evaluation of the statement. 352 /// \param E The expression value which we are tracking 353 /// \param R The bug report to which visitors should be attached. 354 /// \param EnableNullFPSuppression Whether we should employ false positive 355 /// suppression (inlined defensive checks, returned null). 356 /// 357 /// \return Whether or not the function was able to add visitors for this 358 /// statement. Note that returning \c true does not actually imply 359 /// that any visitors were added. 360 bool trackExpressionValue(const ExplodedNode *N, const Expr *E, BugReport &R, 361 bool EnableNullFPSuppression = true); 362 363 const Expr *getDerefExpr(const Stmt *S); 364 365 } // namespace bugreporter 366 367 } // namespace ento 368 369 } // namespace clang 370 371 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H 372