1//===- BugReporterVisitors.h - Generate PathDiagnostics ---------*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file declares BugReporterVisitors, which are used to generate enhanced 10// diagnostic traces. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H 15#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H 16 17#include "clang/Analysis/ProgramPoint.h" 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 26namespace clang { 27 28class BinaryOperator; 29class CFGBlock; 30class DeclRefExpr; 31class Expr; 32class Stmt; 33 34namespace ento { 35 36class PathSensitiveBugReport; 37class BugReporterContext; 38class ExplodedNode; 39class MemRegion; 40class PathDiagnosticPiece; 41using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>; 42 43/// BugReporterVisitors are used to add custom diagnostics along a path. 44class BugReporterVisitor : public llvm::FoldingSetNode { 45public: 46 BugReporterVisitor() = default; 47 BugReporterVisitor(const BugReporterVisitor &) = default; 48 BugReporterVisitor(BugReporterVisitor &&) {} 49 virtual ~BugReporterVisitor(); 50 51 /// Return a diagnostic piece which should be associated with the 52 /// given node. 53 /// Note that this function does *not* get run on the very last node 54 /// of the report, as the PathDiagnosticPiece associated with the 55 /// last node should be unique. 56 /// Use {@code getEndPath} to customize the note associated with the report 57 /// end instead. 58 /// 59 /// The last parameter can be used to register a new visitor with the given 60 /// BugReport while processing a node. 61 virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, 62 BugReporterContext &BRC, 63 PathSensitiveBugReport &BR) = 0; 64 65 /// Last function called on the visitor, no further calls to VisitNode 66 /// would follow. 67 virtual void finalizeVisitor(BugReporterContext &BRC, 68 const ExplodedNode *EndPathNode, 69 PathSensitiveBugReport &BR); 70 71 /// Provide custom definition for the final diagnostic piece on the 72 /// path - the piece, which is displayed before the path is expanded. 73 /// 74 /// NOTE that this function can be implemented on at most one used visitor, 75 /// and otherwise it crahes at runtime. 76 virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, 77 const ExplodedNode *N, 78 PathSensitiveBugReport &BR); 79 80 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0; 81 82 /// Generates the default final diagnostic piece. 83 static PathDiagnosticPieceRef 84 getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N, 85 const PathSensitiveBugReport &BR); 86}; 87 88namespace bugreporter { 89 90/// Specifies the type of tracking for an expression. 91enum class TrackingKind { 92 /// Default tracking kind -- specifies that as much information should be 93 /// gathered about the tracked expression value as possible. 94 Thorough, 95 /// Specifies that a more moderate tracking should be used for the expression 96 /// value. This will essentially make sure that functions relevant to the it 97 /// aren't pruned, but otherwise relies on the user reading the code or 98 /// following the arrows. 99 Condition 100}; 101 102/// Attempts to add visitors to track expression value back to its point of 103/// origin. 104/// 105/// \param N A node "downstream" from the evaluation of the statement. 106/// \param E The expression value which we are tracking 107/// \param R The bug report to which visitors should be attached. 108/// \param EnableNullFPSuppression Whether we should employ false positive 109/// suppression (inlined defensive checks, returned null). 110/// 111/// \return Whether or not the function was able to add visitors for this 112/// statement. Note that returning \c true does not actually imply 113/// that any visitors were added. 114bool trackExpressionValue(const ExplodedNode *N, const Expr *E, 115 PathSensitiveBugReport &R, 116 TrackingKind TKind = TrackingKind::Thorough, 117 bool EnableNullFPSuppression = true); 118 119const Expr *getDerefExpr(const Stmt *S); 120 121} // namespace bugreporter 122 123/// Finds last store into the given region, 124/// which is different from a given symbolic value. 125class FindLastStoreBRVisitor final : public BugReporterVisitor { 126 const MemRegion *R; 127 SVal V; 128 bool Satisfied = false; 129 130 /// If the visitor is tracking the value directly responsible for the 131 /// bug, we are going to employ false positive suppression. 132 bool EnableNullFPSuppression; 133 134 using TrackingKind = bugreporter::TrackingKind; 135 TrackingKind TKind; 136 const StackFrameContext *OriginSFC; 137 138public: 139 /// \param V We're searching for the store where \c R received this value. 140 /// \param R The region we're tracking. 141 /// \param TKind May limit the amount of notes added to the bug report. 142 /// \param OriginSFC Only adds notes when the last store happened in a 143 /// different stackframe to this one. Disregarded if the tracking kind 144 /// is thorough. 145 /// This is useful, because for non-tracked regions, notes about 146 /// changes to its value in a nested stackframe could be pruned, and 147 /// this visitor can prevent that without polluting the bugpath too 148 /// much. 149 FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R, 150 bool InEnableNullFPSuppression, TrackingKind TKind, 151 const StackFrameContext *OriginSFC = nullptr) 152 : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression), 153 TKind(TKind), OriginSFC(OriginSFC) { 154 assert(R); 155 } 156 157 void Profile(llvm::FoldingSetNodeID &ID) const override; 158 159 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 160 BugReporterContext &BRC, 161 PathSensitiveBugReport &BR) override; 162}; 163 164class TrackConstraintBRVisitor final : public BugReporterVisitor { 165 DefinedSVal Constraint; 166 bool Assumption; 167 bool IsSatisfied = false; 168 bool IsZeroCheck; 169 170 /// We should start tracking from the last node along the path in which the 171 /// value is constrained. 172 bool IsTrackingTurnedOn = false; 173 174public: 175 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) 176 : Constraint(constraint), Assumption(assumption), 177 IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {} 178 179 void Profile(llvm::FoldingSetNodeID &ID) const override; 180 181 /// Return the tag associated with this visitor. This tag will be used 182 /// to make all PathDiagnosticPieces created by this visitor. 183 static const char *getTag(); 184 185 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 186 BugReporterContext &BRC, 187 PathSensitiveBugReport &BR) override; 188 189private: 190 /// Checks if the constraint is valid in the current state. 191 bool isUnderconstrained(const ExplodedNode *N) const; 192}; 193 194/// \class NilReceiverBRVisitor 195/// Prints path notes when a message is sent to a nil receiver. 196class NilReceiverBRVisitor final : public BugReporterVisitor { 197public: 198 void Profile(llvm::FoldingSetNodeID &ID) const override { 199 static int x = 0; 200 ID.AddPointer(&x); 201 } 202 203 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 204 BugReporterContext &BRC, 205 PathSensitiveBugReport &BR) override; 206 207 /// If the statement is a message send expression with nil receiver, returns 208 /// the receiver expression. Returns NULL otherwise. 209 static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N); 210}; 211 212/// Visitor that tries to report interesting diagnostics from conditions. 213class ConditionBRVisitor final : public BugReporterVisitor { 214 // FIXME: constexpr initialization isn't supported by MSVC2013. 215 constexpr static llvm::StringLiteral GenericTrueMessage = 216 "Assuming the condition is true"; 217 constexpr static llvm::StringLiteral GenericFalseMessage = 218 "Assuming the condition is false"; 219 220public: 221 void Profile(llvm::FoldingSetNodeID &ID) const override { 222 static int x = 0; 223 ID.AddPointer(&x); 224 } 225 226 /// Return the tag associated with this visitor. This tag will be used 227 /// to make all PathDiagnosticPieces created by this visitor. 228 static const char *getTag(); 229 230 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 231 BugReporterContext &BRC, 232 PathSensitiveBugReport &BR) override; 233 234 PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N, 235 BugReporterContext &BRC, 236 PathSensitiveBugReport &BR); 237 238 PathDiagnosticPieceRef 239 VisitTerminator(const Stmt *Term, const ExplodedNode *N, 240 const CFGBlock *SrcBlk, const CFGBlock *DstBlk, 241 PathSensitiveBugReport &R, BugReporterContext &BRC); 242 243 PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, 244 BugReporterContext &BRC, 245 PathSensitiveBugReport &R, 246 const ExplodedNode *N, bool TookTrue); 247 248 PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, 249 BugReporterContext &BRC, 250 PathSensitiveBugReport &R, 251 const ExplodedNode *N, bool TookTrue, 252 bool IsAssuming); 253 254 PathDiagnosticPieceRef 255 VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr, 256 BugReporterContext &BRC, PathSensitiveBugReport &R, 257 const ExplodedNode *N, bool TookTrue, bool IsAssuming); 258 259 PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const MemberExpr *ME, 260 BugReporterContext &BRC, 261 PathSensitiveBugReport &R, 262 const ExplodedNode *N, bool TookTrue, 263 bool IsAssuming); 264 265 PathDiagnosticPieceRef 266 VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, 267 BugReporterContext &BRC, PathSensitiveBugReport &R, 268 const ExplodedNode *N, bool TookTrue); 269 270 /// Tries to print the value of the given expression. 271 /// 272 /// \param CondVarExpr The expression to print its value. 273 /// \param Out The stream to print. 274 /// \param N The node where we encountered the condition. 275 /// \param TookTrue Whether we took the \c true branch of the condition. 276 /// 277 /// \return Whether the print was successful. (The printing is successful if 278 /// we model the value and we could obtain it.) 279 bool printValue(const Expr *CondVarExpr, raw_ostream &Out, 280 const ExplodedNode *N, bool TookTrue, bool IsAssuming); 281 282 bool patternMatch(const Expr *Ex, 283 const Expr *ParentEx, 284 raw_ostream &Out, 285 BugReporterContext &BRC, 286 PathSensitiveBugReport &R, 287 const ExplodedNode *N, 288 Optional<bool> &prunable, 289 bool IsSameFieldName); 290 291 static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece); 292}; 293 294/// Suppress reports that might lead to known false positives. 295/// 296/// Currently this suppresses reports based on locations of bugs. 297class LikelyFalsePositiveSuppressionBRVisitor final 298 : public BugReporterVisitor { 299public: 300 static void *getTag() { 301 static int Tag = 0; 302 return static_cast<void *>(&Tag); 303 } 304 305 void Profile(llvm::FoldingSetNodeID &ID) const override { 306 ID.AddPointer(getTag()); 307 } 308 309 PathDiagnosticPieceRef VisitNode(const ExplodedNode *, BugReporterContext &, 310 PathSensitiveBugReport &) override { 311 return nullptr; 312 } 313 314 void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N, 315 PathSensitiveBugReport &BR) override; 316}; 317 318/// When a region containing undefined value or '0' value is passed 319/// as an argument in a call, marks the call as interesting. 320/// 321/// As a result, BugReporter will not prune the path through the function even 322/// if the region's contents are not modified/accessed by the call. 323class UndefOrNullArgVisitor final : public BugReporterVisitor { 324 /// The interesting memory region this visitor is tracking. 325 const MemRegion *R; 326 327public: 328 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {} 329 330 void Profile(llvm::FoldingSetNodeID &ID) const override { 331 static int Tag = 0; 332 ID.AddPointer(&Tag); 333 ID.AddPointer(R); 334 } 335 336 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 337 BugReporterContext &BRC, 338 PathSensitiveBugReport &BR) override; 339}; 340 341class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor { 342 /// The symbolic value for which we are tracking constraints. 343 /// This value is constrained to null in the end of path. 344 DefinedSVal V; 345 346 /// Track if we found the node where the constraint was first added. 347 bool IsSatisfied = false; 348 349 /// Since the visitors can be registered on nodes previous to the last 350 /// node in the BugReport, but the path traversal always starts with the last 351 /// node, the visitor invariant (that we start with a node in which V is null) 352 /// might not hold when node visitation starts. We are going to start tracking 353 /// from the last node in which the value is null. 354 bool IsTrackingTurnedOn = false; 355 356public: 357 SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N); 358 359 void Profile(llvm::FoldingSetNodeID &ID) const override; 360 361 /// Return the tag associated with this visitor. This tag will be used 362 /// to make all PathDiagnosticPieces created by this visitor. 363 static const char *getTag(); 364 365 PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, 366 BugReporterContext &BRC, 367 PathSensitiveBugReport &BR) override; 368}; 369 370/// The bug visitor will walk all the nodes in a path and collect all the 371/// constraints. When it reaches the root node, will create a refutation 372/// manager and check if the constraints are satisfiable 373class FalsePositiveRefutationBRVisitor final : public BugReporterVisitor { 374private: 375 /// Holds the constraints in a given path 376 ConstraintRangeTy Constraints; 377 378public: 379 FalsePositiveRefutationBRVisitor(); 380 381 void Profile(llvm::FoldingSetNodeID &ID) const override; 382 383 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 384 BugReporterContext &BRC, 385 PathSensitiveBugReport &BR) override; 386 387 void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode, 388 PathSensitiveBugReport &BR) override; 389}; 390 391 392/// The visitor detects NoteTags and displays the event notes they contain. 393class TagVisitor : public BugReporterVisitor { 394public: 395 void Profile(llvm::FoldingSetNodeID &ID) const override; 396 397 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 398 BugReporterContext &BRC, 399 PathSensitiveBugReport &R) override; 400}; 401 402} // namespace ento 403 404} // namespace clang 405 406#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H 407