Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  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;
  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.  
  183.   static TrackerRef create(PathSensitiveBugReport &Report) {
  184.     return new Tracker(Report);
  185.   }
  186.  
  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.
  199.     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.
  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.
  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.
  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.
  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>
  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>
  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:
  298.   ExpressionHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
  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.
  312.   Tracker &getParentTracker() { return ParentTracker; }
  313. };
  314.  
  315. /// Handles stores during the tracking.
  316. class StoreHandler {
  317. private:
  318.   Tracker &ParentTracker;
  319.  
  320. public:
  321.   StoreHandler(Tracker &ParentTracker) : ParentTracker(ParentTracker) {}
  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.  
  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:
  347.   TrackingBugReporterVisitor(TrackerRef ParentTracker)
  348.       : ParentTracker(ParentTracker) {}
  349.  
  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:
  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:
  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:
  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:
  520.   static void *getTag() {
  521.     static int Tag = 0;
  522.     return static_cast<void *>(&Tag);
  523.   }
  524.  
  525.   void Profile(llvm::FoldingSetNodeID &ID) const override {
  526.     ID.AddPointer(getTag());
  527.   }
  528.  
  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:
  548.   UndefOrNullArgVisitor(const MemRegion *InR) : R(InR) {}
  549.  
  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.
  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).
  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:
  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.