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/IntrusiveRefCntPtr.h" 23 #include "llvm/ADT/STLExtras.h" 24 #include "llvm/ADT/SmallPtrSet.h" 25 #include "llvm/ADT/StringRef.h" 26 #include <list> 27 #include <memory> 28 #include <optional> 29 #include <utility> 30 31 namespace clang { 32 33 class BinaryOperator; 34 class CFGBlock; 35 class DeclRefExpr; 36 class Expr; 37 class Stmt; 38 39 namespace ento { 40 41 class PathSensitiveBugReport; 42 class BugReporterContext; 43 class ExplodedNode; 44 class MemRegion; 45 class PathDiagnosticPiece; 46 using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>; 47 48 /// BugReporterVisitors are used to add custom diagnostics along a path. 49 class BugReporterVisitor : public llvm::FoldingSetNode { 50 public: 51 BugReporterVisitor() = default; 52 BugReporterVisitor(const BugReporterVisitor &) = default; BugReporterVisitor(BugReporterVisitor &&)53 BugReporterVisitor(BugReporterVisitor &&) {} 54 virtual ~BugReporterVisitor(); 55 56 /// Return a diagnostic piece which should be associated with the 57 /// given node. 58 /// Note that this function does *not* get run on the very last node 59 /// of the report, as the PathDiagnosticPiece associated with the 60 /// last node should be unique. 61 /// Use \ref getEndPath to customize the note associated with the report 62 /// end instead. 63 /// 64 /// The last parameter can be used to register a new visitor with the given 65 /// BugReport while processing a node. 66 virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, 67 BugReporterContext &BRC, 68 PathSensitiveBugReport &BR) = 0; 69 70 /// Last function called on the visitor, no further calls to VisitNode 71 /// would follow. 72 virtual void finalizeVisitor(BugReporterContext &BRC, 73 const ExplodedNode *EndPathNode, 74 PathSensitiveBugReport &BR); 75 76 /// Provide custom definition for the final diagnostic piece on the 77 /// path - the piece, which is displayed before the path is expanded. 78 /// 79 /// NOTE that this function can be implemented on at most one used visitor, 80 /// and otherwise it crahes at runtime. 81 virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, 82 const ExplodedNode *N, 83 PathSensitiveBugReport &BR); 84 85 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0; 86 87 /// Generates the default final diagnostic piece. 88 static PathDiagnosticPieceRef 89 getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N, 90 const PathSensitiveBugReport &BR); 91 }; 92 93 namespace bugreporter { 94 95 /// Specifies the type of tracking for an expression. 96 enum class TrackingKind { 97 /// Default tracking kind -- specifies that as much information should be 98 /// gathered about the tracked expression value as possible. 99 Thorough, 100 /// Specifies that a more moderate tracking should be used for the expression 101 /// value. This will essentially make sure that functions relevant to it 102 /// aren't pruned, but otherwise relies on the user reading the code or 103 /// following the arrows. 104 Condition 105 }; 106 107 /// Defines a set of options altering tracking behavior. 108 struct TrackingOptions { 109 /// Specifies the kind of tracking. 110 TrackingKind Kind = TrackingKind::Thorough; 111 /// Specifies whether we should employ false positive suppression 112 /// (inlined defensive checks, returned null). 113 bool EnableNullFPSuppression = true; 114 }; 115 116 /// Describes an event when the value got stored into a memory region. 117 /// 118 /// As opposed to checker checkBind API, it reacts also to binds 119 /// generated by the checker as well. It can be useful when the binding 120 /// happened as a result of evalCall, for example. 121 struct StoreInfo { 122 enum Kind { 123 /// The value got stored into the region during initialization: 124 /// int x = 42; 125 Initialization, 126 /// The value got stored into the region during assignment: 127 /// int x; 128 /// x = 42; 129 Assignment, 130 /// The value got stored into the parameter region as the result 131 /// of a call. 132 CallArgument, 133 /// The value got stored into the region as block capture. 134 /// Block data is modeled as a separate region, thus whenever 135 /// the analyzer sees a captured variable, its value is copied 136 /// into a special block region. 137 BlockCapture 138 }; 139 140 /// The type of store operation. 141 Kind StoreKind; 142 /// The node where the store happened. 143 const ExplodedNode *StoreSite; 144 /// The expression where the value comes from. 145 /// NOTE: might be null. 146 const Expr *SourceOfTheValue; 147 /// Symbolic value that is being stored. 148 SVal Value; 149 /// Memory regions involved in the store operation. 150 /// Dest <- Origin 151 /// NOTE: Origin might be null, when the stored value doesn't come 152 /// from another region. 153 const MemRegion *Dest, *Origin; 154 }; 155 156 class Tracker; 157 using TrackerRef = llvm::IntrusiveRefCntPtr<Tracker>; 158 159 class ExpressionHandler; 160 class StoreHandler; 161 162 /// A generalized component for tracking expressions, values, and stores. 163 /// 164 /// Tracker aimes at providing a sensible set of default behaviors that can be 165 /// used by any checker, while providing mechanisms to hook into any part of the 166 /// tracking process and insert checker-specific logic. 167 class Tracker : public llvm::RefCountedBase<Tracker> { 168 private: 169 using ExpressionHandlerPtr = std::unique_ptr<ExpressionHandler>; 170 using StoreHandlerPtr = std::unique_ptr<StoreHandler>; 171 172 PathSensitiveBugReport &Report; 173 std::list<ExpressionHandlerPtr> ExpressionHandlers; 174 std::list<StoreHandlerPtr> StoreHandlers; 175 176 protected: 177 /// \param Report The bug report to which visitors should be attached. 178 Tracker(PathSensitiveBugReport &Report); 179 180 public: 181 virtual ~Tracker() = default; 182 create(PathSensitiveBugReport & Report)183 static TrackerRef create(PathSensitiveBugReport &Report) { 184 return new Tracker(Report); 185 } 186 getReport()187 PathSensitiveBugReport &getReport() { return Report; } 188 189 /// Describes a tracking result with the most basic information of what was 190 /// actually done (or not done). 191 struct Result { 192 /// Usually it means that the tracker added visitors. 193 bool FoundSomethingToTrack = false; 194 /// Signifies that the tracking was interrupted at some point. 195 /// Usually this information is important only for sub-trackers. 196 bool WasInterrupted = false; 197 198 /// Combines the current result with the given result. combineWithResult199 void combineWith(const Result &Other) { 200 // If we found something in one of the cases, we can 201 // say we found something overall. 202 FoundSomethingToTrack |= Other.FoundSomethingToTrack; 203 // The same goes to the interruption. 204 WasInterrupted |= Other.WasInterrupted; 205 } 206 }; 207 208 /// Track expression value back to its point of origin. 209 /// 210 /// \param E The expression value which we are tracking 211 /// \param N A node "downstream" from the evaluation of the statement. 212 /// \param Opts Tracking options specifying how we want to track the value. 213 virtual Result track(const Expr *E, const ExplodedNode *N, 214 TrackingOptions Opts = {}); 215 216 /// Track how the value got stored into the given region and where it came 217 /// from. 218 /// 219 /// \param V We're searching for the store where \c R received this value. 220 /// \param R The region we're tracking. 221 /// \param Opts Tracking options specifying how we want to track the value. 222 /// \param Origin Only adds notes when the last store happened in a 223 /// different stackframe to this one. Disregarded if the tracking kind 224 /// is thorough. 225 /// This is useful, because for non-tracked regions, notes about 226 /// changes to its value in a nested stackframe could be pruned, and 227 /// this visitor can prevent that without polluting the bugpath too 228 /// much. 229 virtual Result track(SVal V, const MemRegion *R, TrackingOptions Opts = {}, 230 const StackFrameContext *Origin = nullptr); 231 232 /// Handle the store operation and produce the note. 233 /// 234 /// \param SI The information fully describing the store. 235 /// \param Opts Tracking options specifying how we got to it. 236 /// 237 /// NOTE: this method is designed for sub-trackers and visitors. 238 virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC, 239 TrackingOptions Opts); 240 241 /// Add custom expression handler with the highest priority. 242 /// 243 /// It means that it will be asked for handling first, and can prevent 244 /// other handlers from running if decides to interrupt. addHighPriorityHandler(ExpressionHandlerPtr SH)245 void addHighPriorityHandler(ExpressionHandlerPtr SH) { 246 ExpressionHandlers.push_front(std::move(SH)); 247 } 248 249 /// Add custom expression handler with the lowest priority. 250 /// 251 /// It means that it will be asked for handling last, and other handlers can 252 /// prevent it from running if any of them decides to interrupt. addLowPriorityHandler(ExpressionHandlerPtr SH)253 void addLowPriorityHandler(ExpressionHandlerPtr SH) { 254 ExpressionHandlers.push_back(std::move(SH)); 255 } 256 257 /// Add custom store handler with the highest priority. 258 /// 259 /// It means that it will be asked for handling first, and will prevent 260 /// other handlers from running if it produces non-null note. addHighPriorityHandler(StoreHandlerPtr SH)261 void addHighPriorityHandler(StoreHandlerPtr SH) { 262 StoreHandlers.push_front(std::move(SH)); 263 } 264 265 /// Add custom store handler with the lowest priority. 266 /// 267 /// It means that it will be asked for handling last, only 268 /// if all other handlers failed to produce the note. addLowPriorityHandler(StoreHandlerPtr SH)269 void addLowPriorityHandler(StoreHandlerPtr SH) { 270 StoreHandlers.push_back(std::move(SH)); 271 } 272 273 /// Add custom expression/store handler with the highest priority 274 /// 275 /// See other overloads for explanation. 276 template <class HandlerType, class... Args> addHighPriorityHandler(Args &&...ConstructorArgs)277 void addHighPriorityHandler(Args &&... ConstructorArgs) { 278 addHighPriorityHandler(std::make_unique<HandlerType>( 279 *this, std::forward<Args>(ConstructorArgs)...)); 280 } 281 282 /// Add custom expression/store handler with the lowest priority 283 /// 284 /// See other overloads for explanation. 285 template <class HandlerType, class... Args> addLowPriorityHandler(Args &&...ConstructorArgs)286 void addLowPriorityHandler(Args &&... ConstructorArgs) { 287 addLowPriorityHandler(std::make_unique<HandlerType>( 288 *this, std::forward<Args>(ConstructorArgs)...)); 289 } 290 }; 291 292 /// Handles expressions during the tracking. 293 class ExpressionHandler { 294 private: 295 Tracker &ParentTracker; 296 297 public: ExpressionHandler(Tracker & ParentTracker)298 ExpressionHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {} ~ExpressionHandler()299 virtual ~ExpressionHandler() {} 300 301 /// Handle the given expression from the given node. 302 /// 303 /// \param E The expression value which we are tracking 304 /// \param Original A node "downstream" where the tracking started. 305 /// \param ExprNode A node where the evaluation of \c E actually happens. 306 /// \param Opts Tracking options specifying how we are tracking the value. 307 virtual Tracker::Result handle(const Expr *E, const ExplodedNode *Original, 308 const ExplodedNode *ExprNode, 309 TrackingOptions Opts) = 0; 310 311 /// \Return the tracker that initiated the process. getParentTracker()312 Tracker &getParentTracker() { return ParentTracker; } 313 }; 314 315 /// Handles stores during the tracking. 316 class StoreHandler { 317 private: 318 Tracker &ParentTracker; 319 320 public: StoreHandler(Tracker & ParentTracker)321 StoreHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {} ~StoreHandler()322 virtual ~StoreHandler() {} 323 324 /// Handle the given store and produce the node. 325 /// 326 /// \param SI The information fully describing the store. 327 /// \param Opts Tracking options specifying how we are tracking the value. 328 /// 329 /// \return the produced note, null if the handler doesn't support this kind 330 /// of stores. 331 virtual PathDiagnosticPieceRef handle(StoreInfo SI, BugReporterContext &BRC, 332 TrackingOptions Opts) = 0; 333 getParentTracker()334 Tracker &getParentTracker() { return ParentTracker; } 335 336 protected: 337 PathDiagnosticPieceRef constructNote(StoreInfo SI, BugReporterContext &BRC, 338 StringRef NodeText); 339 }; 340 341 /// Visitor that tracks expressions and values. 342 class TrackingBugReporterVisitor : public BugReporterVisitor { 343 private: 344 TrackerRef ParentTracker; 345 346 public: TrackingBugReporterVisitor(TrackerRef ParentTracker)347 TrackingBugReporterVisitor(TrackerRef ParentTracker) 348 : ParentTracker(ParentTracker) {} 349 getParentTracker()350 Tracker &getParentTracker() { return *ParentTracker; } 351 }; 352 353 /// Attempts to add visitors to track expression value back to its point of 354 /// origin. 355 /// 356 /// \param N A node "downstream" from the evaluation of the statement. 357 /// \param E The expression value which we are tracking 358 /// \param R The bug report to which visitors should be attached. 359 /// \param Opts Tracking options specifying how we are tracking the value. 360 /// 361 /// \return Whether or not the function was able to add visitors for this 362 /// statement. Note that returning \c true does not actually imply 363 /// that any visitors were added. 364 bool trackExpressionValue(const ExplodedNode *N, const Expr *E, 365 PathSensitiveBugReport &R, TrackingOptions Opts = {}); 366 367 /// Track how the value got stored into the given region and where it came 368 /// from. 369 /// 370 /// \param V We're searching for the store where \c R received this value. 371 /// \param R The region we're tracking. 372 /// \param Opts Tracking options specifying how we want to track the value. 373 /// \param Origin Only adds notes when the last store happened in a 374 /// different stackframe to this one. Disregarded if the tracking kind 375 /// is thorough. 376 /// This is useful, because for non-tracked regions, notes about 377 /// changes to its value in a nested stackframe could be pruned, and 378 /// this visitor can prevent that without polluting the bugpath too 379 /// much. 380 void trackStoredValue(KnownSVal V, const MemRegion *R, 381 PathSensitiveBugReport &Report, TrackingOptions Opts = {}, 382 const StackFrameContext *Origin = nullptr); 383 384 const Expr *getDerefExpr(const Stmt *S); 385 386 } // namespace bugreporter 387 388 class TrackConstraintBRVisitor final : public BugReporterVisitor { 389 DefinedSVal Constraint; 390 bool Assumption; 391 bool IsSatisfied = false; 392 bool IsZeroCheck; 393 394 /// We should start tracking from the last node along the path in which the 395 /// value is constrained. 396 bool IsTrackingTurnedOn = false; 397 398 public: TrackConstraintBRVisitor(DefinedSVal constraint,bool assumption)399 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) 400 : Constraint(constraint), Assumption(assumption), 401 IsZeroCheck(!Assumption && isa<Loc>(Constraint)) {} 402 403 void Profile(llvm::FoldingSetNodeID &ID) const override; 404 405 /// Return the tag associated with this visitor. This tag will be used 406 /// to make all PathDiagnosticPieces created by this visitor. 407 static const char *getTag(); 408 409 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 410 BugReporterContext &BRC, 411 PathSensitiveBugReport &BR) override; 412 413 private: 414 /// Checks if the constraint is valid in the current state. 415 bool isUnderconstrained(const ExplodedNode *N) const; 416 }; 417 418 /// \class NilReceiverBRVisitor 419 /// Prints path notes when a message is sent to a nil receiver. 420 class NilReceiverBRVisitor final : public BugReporterVisitor { 421 public: Profile(llvm::FoldingSetNodeID & ID)422 void Profile(llvm::FoldingSetNodeID &ID) const override { 423 static int x = 0; 424 ID.AddPointer(&x); 425 } 426 427 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 428 BugReporterContext &BRC, 429 PathSensitiveBugReport &BR) override; 430 431 /// If the statement is a message send expression with nil receiver, returns 432 /// the receiver expression. Returns NULL otherwise. 433 static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N); 434 }; 435 436 /// Visitor that tries to report interesting diagnostics from conditions. 437 class ConditionBRVisitor final : public BugReporterVisitor { 438 // FIXME: constexpr initialization isn't supported by MSVC2013. 439 constexpr static llvm::StringLiteral GenericTrueMessage = 440 "Assuming the condition is true"; 441 constexpr static llvm::StringLiteral GenericFalseMessage = 442 "Assuming the condition is false"; 443 444 public: Profile(llvm::FoldingSetNodeID & ID)445 void Profile(llvm::FoldingSetNodeID &ID) const override { 446 static int x = 0; 447 ID.AddPointer(&x); 448 } 449 450 /// Return the tag associated with this visitor. This tag will be used 451 /// to make all PathDiagnosticPieces created by this visitor. 452 static const char *getTag(); 453 454 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 455 BugReporterContext &BRC, 456 PathSensitiveBugReport &BR) override; 457 458 PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N, 459 BugReporterContext &BRC, 460 PathSensitiveBugReport &BR); 461 462 PathDiagnosticPieceRef 463 VisitTerminator(const Stmt *Term, const ExplodedNode *N, 464 const CFGBlock *SrcBlk, const CFGBlock *DstBlk, 465 PathSensitiveBugReport &R, BugReporterContext &BRC); 466 467 PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, 468 BugReporterContext &BRC, 469 PathSensitiveBugReport &R, 470 const ExplodedNode *N, bool TookTrue); 471 472 PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, 473 BugReporterContext &BRC, 474 PathSensitiveBugReport &R, 475 const ExplodedNode *N, bool TookTrue, 476 bool IsAssuming); 477 478 PathDiagnosticPieceRef 479 VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr, 480 BugReporterContext &BRC, PathSensitiveBugReport &R, 481 const ExplodedNode *N, bool TookTrue, bool IsAssuming); 482 483 PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const MemberExpr *ME, 484 BugReporterContext &BRC, 485 PathSensitiveBugReport &R, 486 const ExplodedNode *N, bool TookTrue, 487 bool IsAssuming); 488 489 PathDiagnosticPieceRef 490 VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, 491 BugReporterContext &BRC, PathSensitiveBugReport &R, 492 const ExplodedNode *N, bool TookTrue); 493 494 /// Tries to print the value of the given expression. 495 /// 496 /// \param CondVarExpr The expression to print its value. 497 /// \param Out The stream to print. 498 /// \param N The node where we encountered the condition. 499 /// \param TookTrue Whether we took the \c true branch of the condition. 500 /// 501 /// \return Whether the print was successful. (The printing is successful if 502 /// we model the value and we could obtain it.) 503 bool printValue(const Expr *CondVarExpr, raw_ostream &Out, 504 const ExplodedNode *N, bool TookTrue, bool IsAssuming); 505 506 bool patternMatch(const Expr *Ex, const Expr *ParentEx, raw_ostream &Out, 507 BugReporterContext &BRC, PathSensitiveBugReport &R, 508 const ExplodedNode *N, std::optional<bool> &prunable, 509 bool IsSameFieldName); 510 511 static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece); 512 }; 513 514 /// Suppress reports that might lead to known false positives. 515 /// 516 /// Currently this suppresses reports based on locations of bugs. 517 class LikelyFalsePositiveSuppressionBRVisitor final 518 : public BugReporterVisitor { 519 public: getTag()520 static void *getTag() { 521 static int Tag = 0; 522 return static_cast<void *>(&Tag); 523 } 524 Profile(llvm::FoldingSetNodeID & ID)525 void Profile(llvm::FoldingSetNodeID &ID) const override { 526 ID.AddPointer(getTag()); 527 } 528 VisitNode(const ExplodedNode *,BugReporterContext &,PathSensitiveBugReport &)529 PathDiagnosticPieceRef VisitNode(const ExplodedNode *, BugReporterContext &, 530 PathSensitiveBugReport &) override { 531 return nullptr; 532 } 533 534 void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N, 535 PathSensitiveBugReport &BR) override; 536 }; 537 538 /// When a region containing undefined value or '0' value is passed 539 /// as an argument in a call, marks the call as interesting. 540 /// 541 /// As a result, BugReporter will not prune the path through the function even 542 /// if the region's contents are not modified/accessed by the call. 543 class UndefOrNullArgVisitor final : public BugReporterVisitor { 544 /// The interesting memory region this visitor is tracking. 545 const MemRegion *R; 546 547 public: UndefOrNullArgVisitor(const MemRegion * InR)548 UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {} 549 Profile(llvm::FoldingSetNodeID & ID)550 void Profile(llvm::FoldingSetNodeID &ID) const override { 551 static int Tag = 0; 552 ID.AddPointer(&Tag); 553 ID.AddPointer(R); 554 } 555 556 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 557 BugReporterContext &BRC, 558 PathSensitiveBugReport &BR) override; 559 }; 560 561 class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor { 562 /// The symbolic value for which we are tracking constraints. 563 /// This value is constrained to null in the end of path. 564 DefinedSVal V; 565 566 /// Track if we found the node where the constraint was first added. 567 bool IsSatisfied = false; 568 569 /// Since the visitors can be registered on nodes previous to the last 570 /// node in the BugReport, but the path traversal always starts with the last 571 /// node, the visitor invariant (that we start with a node in which V is null) 572 /// might not hold when node visitation starts. We are going to start tracking 573 /// from the last node in which the value is null. 574 bool IsTrackingTurnedOn = false; 575 576 public: 577 SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N); 578 579 void Profile(llvm::FoldingSetNodeID &ID) const override; 580 581 /// Return the tag associated with this visitor. This tag will be used 582 /// to make all PathDiagnosticPieces created by this visitor. 583 static const char *getTag(); 584 585 PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, 586 BugReporterContext &BRC, 587 PathSensitiveBugReport &BR) override; 588 }; 589 590 /// The bug visitor will walk all the nodes in a path and collect all the 591 /// constraints. When it reaches the root node, will create a refutation 592 /// manager and check if the constraints are satisfiable 593 class FalsePositiveRefutationBRVisitor final : public BugReporterVisitor { 594 private: 595 /// Holds the constraints in a given path 596 ConstraintMap Constraints; 597 598 public: 599 FalsePositiveRefutationBRVisitor(); 600 601 void Profile(llvm::FoldingSetNodeID &ID) const override; 602 603 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 604 BugReporterContext &BRC, 605 PathSensitiveBugReport &BR) override; 606 607 void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode, 608 PathSensitiveBugReport &BR) override; 609 void addConstraints(const ExplodedNode *N, 610 bool OverwriteConstraintsOnExistingSyms); 611 }; 612 613 /// The visitor detects NoteTags and displays the event notes they contain. 614 class TagVisitor : public BugReporterVisitor { 615 public: 616 void Profile(llvm::FoldingSetNodeID &ID) const override; 617 618 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 619 BugReporterContext &BRC, 620 PathSensitiveBugReport &R) override; 621 }; 622 623 class ObjCMethodCall; 624 class CXXConstructorCall; 625 626 /// Put a diagnostic on return statement (or on } in its absence) of all inlined 627 /// functions for which some property remained unchanged. 628 /// Resulting diagnostics may read such as "Returning without writing to X". 629 /// 630 /// Descendants can define what a "state change is", like a change of value 631 /// to a memory region, liveness, etc. For function calls where the state did 632 /// not change as defined, a custom note may be constructed. 633 /// 634 /// For a minimal example, check out 635 /// clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp. 636 class NoStateChangeFuncVisitor : public BugReporterVisitor { 637 private: 638 /// Frames modifying the state as defined in \c wasModifiedBeforeCallExit. 639 /// This visitor generates a note only if a function does *not* change the 640 /// state that way. This information is not immediately available 641 /// by looking at the node associated with the exit from the function 642 /// (usually the return statement). To avoid recomputing the same information 643 /// many times (going up the path for each node and checking whether the 644 /// region was written into) we instead lazily compute the stack frames 645 /// along the path. 646 // TODO: Can't we just use a map instead? This is likely not as cheap as it 647 // makes the code difficult to read. 648 llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifying; 649 llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifyingCalculated; 650 651 /// Check and lazily calculate whether the state is modified in the stack 652 /// frame to which \p CallExitBeginN belongs. 653 /// The calculation is cached in FramesModifying. 654 bool isModifiedInFrame(const ExplodedNode *CallExitBeginN); 655 656 void markFrameAsModifying(const StackFrameContext *SCtx); 657 658 /// Write to \c FramesModifying all stack frames along the path in the current 659 /// stack frame which modifies the state. 660 void findModifyingFrames(const ExplodedNode *const CallExitBeginN); 661 662 protected: 663 bugreporter::TrackingKind TKind; 664 665 /// \return Whether the state was modified from the current node, \p CurrN, to 666 /// the end of the stack frame, at \p CallExitBeginN. \p CurrN and 667 /// \p CallExitBeginN are always in the same stack frame. 668 /// Clients should override this callback when a state change is important 669 /// not only on the entire function call, but inside of it as well. 670 /// Example: we may want to leave a note about the lack of locking/unlocking 671 /// on a particular mutex, but not if inside the function its state was 672 /// changed, but also restored. wasModifiedInFunction() wouldn't know of this 673 /// change. wasModifiedBeforeCallExit(const ExplodedNode * CurrN,const ExplodedNode * CallExitBeginN)674 virtual bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN, 675 const ExplodedNode *CallExitBeginN) { 676 return false; 677 } 678 679 /// \return Whether the state was modified in the inlined function call in 680 /// between \p CallEnterN and \p CallExitEndN. Mind that the stack frame 681 /// retrieved from a CallEnterN and CallExitEndN is the *caller's* stack 682 /// frame! The inlined function's stack should be retrieved from either the 683 /// immediate successor to \p CallEnterN or immediate predecessor to 684 /// \p CallExitEndN. 685 /// Clients should override this function if a state changes local to the 686 /// inlined function are not interesting, only the change occuring as a 687 /// result of it. 688 /// Example: we want to leave a not about a leaked resource object not being 689 /// deallocated / its ownership changed inside a function, and we don't care 690 /// if it was assigned to a local variable (its change in ownership is 691 /// inconsequential). wasModifiedInFunction(const ExplodedNode * CallEnterN,const ExplodedNode * CallExitEndN)692 virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN, 693 const ExplodedNode *CallExitEndN) { 694 return false; 695 } 696 697 /// Consume the information on the non-modifying stack frame in order to 698 /// either emit a note or not. May suppress the report entirely. 699 /// \return Diagnostics piece for the unmodified state in the current 700 /// function, if it decides to emit one. A good description might start with 701 /// "Returning without...". 702 virtual PathDiagnosticPieceRef 703 maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R, 704 const ObjCMethodCall &Call, 705 const ExplodedNode *N) = 0; 706 707 /// Consume the information on the non-modifying stack frame in order to 708 /// either emit a note or not. May suppress the report entirely. 709 /// \return Diagnostics piece for the unmodified state in the current 710 /// function, if it decides to emit one. A good description might start with 711 /// "Returning without...". 712 virtual PathDiagnosticPieceRef 713 maybeEmitNoteForCXXThis(PathSensitiveBugReport &R, 714 const CXXConstructorCall &Call, 715 const ExplodedNode *N) = 0; 716 717 /// Consume the information on the non-modifying stack frame in order to 718 /// either emit a note or not. May suppress the report entirely. 719 /// \return Diagnostics piece for the unmodified state in the current 720 /// function, if it decides to emit one. A good description might start with 721 /// "Returning without...". 722 virtual PathDiagnosticPieceRef 723 maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call, 724 const ExplodedNode *N) = 0; 725 726 public: NoStateChangeFuncVisitor(bugreporter::TrackingKind TKind)727 NoStateChangeFuncVisitor(bugreporter::TrackingKind TKind) : TKind(TKind) {} 728 729 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 730 BugReporterContext &BR, 731 PathSensitiveBugReport &R) final; 732 }; 733 734 } // namespace ento 735 } // namespace clang 736 737 #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H 738