vsavchenko updated this revision to Diff 351102.
vsavchenko added a comment.

Rebase and change `KnownSVal` to `SVal` in `trackStoredValue`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103616/new/

https://reviews.llvm.org/D103616

Files:
  clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
  
clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
  clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
  clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1488,8 +1488,8 @@
     if (!IsParam)
       InitE = InitE->IgnoreParenCasts();
 
-    bugreporter::trackExpressionValue(StoreSite, InitE, BR, TKind,
-                                      EnableNullFPSuppression);
+    getParentTracker().track(InitE, StoreSite,
+                             {TKind, EnableNullFPSuppression});
   }
 
   // Let's try to find the region where the value came from.
@@ -1588,8 +1588,8 @@
               dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
           if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
             if (auto KV = State->getSVal(OriginalR).getAs<KnownSVal>())
-              BR.addVisitor<FindLastStoreBRVisitor>(
-                  *KV, OriginalR, EnableNullFPSuppression, TKind, OriginSFC);
+              getParentTracker().track(
+                  *KV, OriginalR, {TKind, EnableNullFPSuppression}, OriginSFC);
           }
         }
       }
@@ -2050,7 +2050,166 @@
 //                            Tracker implementation
 //===----------------------------------------------------------------------===//
 
+class DefaultExpressionHandler final : public ExpressionHandler {
+public:
+  using ExpressionHandler::ExpressionHandler;
+
+  Tracker::Result handle(const Expr *Inner, const ExplodedNode *InputNode,
+                         const ExplodedNode *LVNode,
+                         TrackingOptions Opts) override {
+    ProgramStateRef LVState = LVNode->getState();
+    const StackFrameContext *SFC = LVNode->getStackFrame();
+    PathSensitiveBugReport &Report = getParentTracker().getReport();
+    Tracker::Result Result;
+
+    // We only track expressions if we believe that they are important. Chances
+    // are good that control dependencies to the tracking point are also
+    // important because of this, let's explain why we believe control reached
+    // this point.
+    // TODO: Shouldn't we track control dependencies of every bug location,
+    // rather than only tracked expressions?
+    if (LVState->getAnalysisManager()
+            .getAnalyzerOptions()
+            .ShouldTrackConditions) {
+      Report.addVisitor<TrackControlDependencyCondBRVisitor>(InputNode);
+      Result.FoundSomethingToTrack = true;
+    }
+
+    // The message send could be nil due to the receiver being nil.
+    // At this point in the path, the receiver should be live since we are at
+    // the message send expr. If it is nil, start tracking it.
+    if (const Expr *Receiver =
+            NilReceiverBRVisitor::getNilReceiver(Inner, LVNode))
+      Result.combineWith(getParentTracker().track(Receiver, LVNode, Opts));
+
+    // Track the index if this is an array subscript.
+    if (const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
+      Result.combineWith(getParentTracker().track(
+          Arr->getIdx(), LVNode,
+          {Opts.Kind, /*EnableNullFPSuppression*/ false}));
+
+    // See if the expression we're interested refers to a variable.
+    // If so, we can track both its contents and constraints on its value.
+    if (ExplodedGraph::isInterestingLValueExpr(Inner)) {
+      SVal LVal = LVNode->getSVal(Inner);
+
+      const MemRegion *RR = getLocationRegionIfReference(Inner, LVNode);
+      bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
+
+      // If this is a C++ reference to a null pointer, we are tracking the
+      // pointer. In addition, we should find the store at which the reference
+      // got initialized.
+      if (RR && !LVIsNull)
+        Result.combineWith(getParentTracker().track(LVal, RR, Opts, SFC));
+
+      // In case of C++ references, we want to differentiate between a null
+      // reference and reference to null pointer.
+      // If the LVal is null, check if we are dealing with null reference.
+      // For those, we want to track the location of the reference.
+      const MemRegion *R =
+          (RR && LVIsNull) ? RR : LVNode->getSVal(Inner).getAsRegion();
+
+      if (R) {
+
+        // Mark both the variable region and its contents as interesting.
+        SVal V = LVState->getRawSVal(loc::MemRegionVal(R));
+        Report.addVisitor<NoStoreFuncVisitor>(cast<SubRegion>(R), Opts.Kind);
+
+        // When we got here, we do have something to track, and we will
+        // interrupt.
+        Result.FoundSomethingToTrack = true;
+        Result.WasInterrupted = true;
+
+        MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
+            LVNode, R, Opts.EnableNullFPSuppression, Report, V);
+
+        Report.markInteresting(V, Opts.Kind);
+        Report.addVisitor<UndefOrNullArgVisitor>(R);
+
+        // If the contents are symbolic and null, find out when they became
+        // null.
+        if (V.getAsLocSymbol(/*IncludeBaseRegions=*/true))
+          if (LVState->isNull(V).isConstrainedTrue())
+            Report.addVisitor<TrackConstraintBRVisitor>(V.castAs<DefinedSVal>(),
+                                                        false);
+
+        // Add visitor, which will suppress inline defensive checks.
+        if (auto DV = V.getAs<DefinedSVal>())
+          if (!DV->isZeroConstant() && Opts.EnableNullFPSuppression)
+            // Note that LVNode may be too late (i.e., too far from the
+            // InputNode) because the lvalue may have been computed before the
+            // inlined call was evaluated. InputNode may as well be too early
+            // here, because the symbol is already dead; this, however, is fine
+            // because we can still find the node in which it collapsed to null
+            // previously.
+            Report.addVisitor<SuppressInlineDefensiveChecksVisitor>(*DV,
+                                                                    InputNode);
+
+        getParentTracker().track(V, R, Opts, SFC);
+
+        return Result;
+      }
+    }
+
+    // If the expression is not an "lvalue expression", we can still
+    // track the constraints on its contents.
+    SVal V = LVState->getSValAsScalarOrLoc(Inner, LVNode->getLocationContext());
+
+    ReturnVisitor::addVisitorIfNecessary(
+        LVNode, Inner, Report, Opts.EnableNullFPSuppression, Opts.Kind);
+
+    // Is it a symbolic value?
+    if (auto L = V.getAs<loc::MemRegionVal>()) {
+      // FIXME: this is a hack for fixing a later crash when attempting to
+      // dereference a void* pointer.
+      // We should not try to dereference pointers at all when we don't care
+      // what is written inside the pointer.
+      bool CanDereference = true;
+      if (const auto *SR = L->getRegionAs<SymbolicRegion>()) {
+        if (SR->getSymbol()->getType()->getPointeeType()->isVoidType())
+          CanDereference = false;
+      } else if (L->getRegionAs<AllocaRegion>())
+        CanDereference = false;
+
+      // At this point we are dealing with the region's LValue.
+      // However, if the rvalue is a symbolic region, we should track it as
+      // well. Try to use the correct type when looking up the value.
+      SVal RVal;
+      if (ExplodedGraph::isInterestingLValueExpr(Inner))
+        RVal = LVState->getRawSVal(L.getValue(), Inner->getType());
+      else if (CanDereference)
+        RVal = LVState->getSVal(L->getRegion());
+
+      if (CanDereference) {
+        Report.addVisitor<UndefOrNullArgVisitor>(L->getRegion());
+        Result.FoundSomethingToTrack = true;
+
+        if (auto KV = RVal.getAs<KnownSVal>())
+          Result.combineWith(
+              getParentTracker().track(*KV, L->getRegion(), Opts, SFC));
+      }
+
+      const MemRegion *RegionRVal = RVal.getAsRegion();
+      if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
+        Report.markInteresting(RegionRVal, Opts.Kind);
+        Report.addVisitor<TrackConstraintBRVisitor>(
+            loc::MemRegionVal(RegionRVal),
+            /*assumption=*/false);
+        Result.FoundSomethingToTrack = true;
+      }
+    }
+
+    if (Inner->isRValue())
+      // TODO: Incorporate as Handler
+      trackRValueExpression(LVNode, Inner, Report, Opts.Kind,
+                            Opts.EnableNullFPSuppression);
+
+    return Result;
+  }
+};
+
 Tracker::Tracker(PathSensitiveBugReport &Report) : Report(Report) {
+  addHighPriorityHandler<DefaultExpressionHandler>();
   // TODO: split trackExpressionValue and FindLastStoreBRVisitor into handlers
   //       and add them here.
 }
@@ -2078,7 +2237,11 @@
 
 Tracker::Result Tracker::track(SVal V, const MemRegion *R, TrackingOptions Opts,
                                const StackFrameContext *Origin) {
-  // TODO: support this operation after dismantling FindLastStoreBRVisitor
+  if (auto KV = V.getAs<KnownSVal>()) {
+    Report.addVisitor<FindLastStoreBRVisitor>(
+        this, *KV, R, Opts.EnableNullFPSuppression, Opts.Kind, Origin);
+    return {true};
+  }
   return {};
 }
 
@@ -2099,147 +2262,16 @@
                                        bugreporter::TrackingKind TKind,
                                        bool EnableNullFPSuppression) {
 
-  if (!E || !InputNode)
-    return false;
-
-  const Expr *Inner = peelOffOuterExpr(E, InputNode);
-  const ExplodedNode *LVNode = findNodeForExpression(InputNode, Inner);
-  if (!LVNode)
-    return false;
-
-  ProgramStateRef LVState = LVNode->getState();
-  const StackFrameContext *SFC = LVNode->getStackFrame();
-
-  // We only track expressions if we believe that they are important. Chances
-  // are good that control dependencies to the tracking point are also important
-  // because of this, let's explain why we believe control reached this point.
-  // TODO: Shouldn't we track control dependencies of every bug location, rather
-  // than only tracked expressions?
-  if (LVState->getAnalysisManager().getAnalyzerOptions().ShouldTrackConditions)
-    report.addVisitor<TrackControlDependencyCondBRVisitor>(InputNode);
-
-  // The message send could be nil due to the receiver being nil.
-  // At this point in the path, the receiver should be live since we are at the
-  // message send expr. If it is nil, start tracking it.
-  if (const Expr *Receiver = NilReceiverBRVisitor::getNilReceiver(Inner, LVNode))
-    trackExpressionValue(
-        LVNode, Receiver, report, TKind, EnableNullFPSuppression);
-
-  // Track the index if this is an array subscript.
-  if (const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
-    trackExpressionValue(
-        LVNode, Arr->getIdx(), report, TKind, /*EnableNullFPSuppression*/false);
-
-  // See if the expression we're interested refers to a variable.
-  // If so, we can track both its contents and constraints on its value.
-  if (ExplodedGraph::isInterestingLValueExpr(Inner)) {
-    SVal LVal = LVNode->getSVal(Inner);
-
-    const MemRegion *RR = getLocationRegionIfReference(Inner, LVNode);
-    bool LVIsNull = LVState->isNull(LVal).isConstrainedTrue();
-
-    // If this is a C++ reference to a null pointer, we are tracking the
-    // pointer. In addition, we should find the store at which the reference
-    // got initialized.
-    if (RR && !LVIsNull)
-      if (auto KV = LVal.getAs<KnownSVal>())
-        report.addVisitor<FindLastStoreBRVisitor>(
-            *KV, RR, EnableNullFPSuppression, TKind, SFC);
-
-    // In case of C++ references, we want to differentiate between a null
-    // reference and reference to null pointer.
-    // If the LVal is null, check if we are dealing with null reference.
-    // For those, we want to track the location of the reference.
-    const MemRegion *R = (RR && LVIsNull) ? RR :
-        LVNode->getSVal(Inner).getAsRegion();
-
-    if (R) {
-
-      // Mark both the variable region and its contents as interesting.
-      SVal V = LVState->getRawSVal(loc::MemRegionVal(R));
-      report.addVisitor<NoStoreFuncVisitor>(cast<SubRegion>(R), TKind);
-
-      MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
-          LVNode, R, EnableNullFPSuppression, report, V);
-
-      report.markInteresting(V, TKind);
-      report.addVisitor<UndefOrNullArgVisitor>(R);
-
-      // If the contents are symbolic and null, find out when they became null.
-      if (V.getAsLocSymbol(/*IncludeBaseRegions=*/true))
-        if (LVState->isNull(V).isConstrainedTrue())
-          report.addVisitor<TrackConstraintBRVisitor>(V.castAs<DefinedSVal>(),
-                                                      false);
-
-      // Add visitor, which will suppress inline defensive checks.
-      if (auto DV = V.getAs<DefinedSVal>())
-        if (!DV->isZeroConstant() && EnableNullFPSuppression) {
-          // Note that LVNode may be too late (i.e., too far from the InputNode)
-          // because the lvalue may have been computed before the inlined call
-          // was evaluated. InputNode may as well be too early here, because
-          // the symbol is already dead; this, however, is fine because we can
-          // still find the node in which it collapsed to null previously.
-          report.addVisitor<SuppressInlineDefensiveChecksVisitor>(*DV,
-                                                                  InputNode);
-        }
-
-      if (auto KV = V.getAs<KnownSVal>())
-        report.addVisitor<FindLastStoreBRVisitor>(
-            *KV, R, EnableNullFPSuppression, TKind, SFC);
-      return true;
-    }
-  }
-
-  // If the expression is not an "lvalue expression", we can still
-  // track the constraints on its contents.
-  SVal V = LVState->getSValAsScalarOrLoc(Inner, LVNode->getLocationContext());
-
-  ReturnVisitor::addVisitorIfNecessary(
-    LVNode, Inner, report, EnableNullFPSuppression, TKind);
-
-  // Is it a symbolic value?
-  if (auto L = V.getAs<loc::MemRegionVal>()) {
-    // FIXME: this is a hack for fixing a later crash when attempting to
-    // dereference a void* pointer.
-    // We should not try to dereference pointers at all when we don't care
-    // what is written inside the pointer.
-    bool CanDereference = true;
-    if (const auto *SR = L->getRegionAs<SymbolicRegion>()) {
-      if (SR->getSymbol()->getType()->getPointeeType()->isVoidType())
-        CanDereference = false;
-    } else if (L->getRegionAs<AllocaRegion>())
-      CanDereference = false;
-
-    // At this point we are dealing with the region's LValue.
-    // However, if the rvalue is a symbolic region, we should track it as well.
-    // Try to use the correct type when looking up the value.
-    SVal RVal;
-    if (ExplodedGraph::isInterestingLValueExpr(Inner))
-      RVal = LVState->getRawSVal(L.getValue(), Inner->getType());
-    else if (CanDereference)
-      RVal = LVState->getSVal(L->getRegion());
-
-    if (CanDereference) {
-      report.addVisitor<UndefOrNullArgVisitor>(L->getRegion());
-
-      if (auto KV = RVal.getAs<KnownSVal>())
-        report.addVisitor<FindLastStoreBRVisitor>(
-            *KV, L->getRegion(), EnableNullFPSuppression, TKind, SFC);
-    }
-
-    const MemRegion *RegionRVal = RVal.getAsRegion();
-    if (isa_and_nonnull<SymbolicRegion>(RegionRVal)) {
-      report.markInteresting(RegionRVal, TKind);
-      report.addVisitor<TrackConstraintBRVisitor>(loc::MemRegionVal(RegionRVal),
-                                                  /*assumption=*/false);
-    }
-  }
-
-  if (Inner->isRValue())
-    trackRValueExpression(LVNode, Inner, report, TKind,
-                          EnableNullFPSuppression);
+  return Tracker::create(report)
+      ->track(E, InputNode, {TKind, EnableNullFPSuppression})
+      .FoundSomethingToTrack;
+}
 
-  return true;
+void bugreporter::trackStoredValue(SVal V, const MemRegion *R,
+                                   PathSensitiveBugReport &Report,
+                                   TrackingOptions Opts,
+                                   const StackFrameContext *Origin) {
+  Tracker::create(Report)->track(V, R, Opts, Origin);
 }
 
 //===----------------------------------------------------------------------===//
Index: clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -86,9 +86,9 @@
         auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
         if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
           R->addRange(Ex->getSourceRange());
-        R->addVisitor(std::make_unique<FindLastStoreBRVisitor>(
-            *V, VR, /*EnableNullFPSuppression*/ false,
-            bugreporter::TrackingKind::Thorough));
+        bugreporter::trackStoredValue(*V, VR, *R,
+                                      {bugreporter::TrackingKind::Thorough,
+                                       /*EnableNullFPSuppression*/ false});
         R->disablePathPruning();
         // need location of block
         C.emitReport(std::move(R));
Index: clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -980,13 +980,12 @@
     // got from one to another.
     //
     // NOTE: We use the actual SVal stored in AllocBindingToReport here because
-    //       FindLastStoreBRVisitor compares SVal's and it can get trickier for
+    //       trackStoredValue compares SVal's and it can get trickier for
     //       something like derived regions if we want to construct SVal from
     //       Sym. Instead, we take the value that is definitely stored in that
-    //       region, thus guaranteeing that FindLastStoreBRVisitor will work.
-    addVisitor<FindLastStoreBRVisitor>(
-        AllVarBindings[0].second.castAs<KnownSVal>(), AllocBindingToReport,
-        false, bugreporter::TrackingKind::Thorough);
+    //       region, thus guaranteeing that trackStoredValue will work.
+    bugreporter::trackStoredValue(AllVarBindings[0].second,
+                                  AllocBindingToReport, *this);
   } else {
     AllocBindingToReport = AllocFirstBinding;
   }
Index: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -19,6 +19,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 #include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include <list>
@@ -147,6 +148,9 @@
   const MemRegion *Dest, *Origin;
 };
 
+class Tracker;
+using TrackerRef = llvm::IntrusiveRefCntPtr<Tracker>;
+
 class ExpressionHandler;
 class StoreHandler;
 
@@ -155,7 +159,7 @@
 /// Tracker aimes at providing a sensible set of default behaviors that can be
 /// used by any checker, while providing mechanisms to hook into any part of the
 /// tracking process and insert checker-specific logic.
-class Tracker {
+class Tracker : public llvm::RefCountedBase<Tracker> {
 private:
   using ExpressionHandlerPtr = std::unique_ptr<ExpressionHandler>;
   using StoreHandlerPtr = std::unique_ptr<StoreHandler>;
@@ -164,11 +168,17 @@
   std::list<ExpressionHandlerPtr> ExpressionHandlers;
   std::list<StoreHandlerPtr> StoreHandlers;
 
-public:
+protected:
   /// \param Report The bug report to which visitors should be attached.
   Tracker(PathSensitiveBugReport &Report);
+
+public:
   virtual ~Tracker() = default;
 
+  static TrackerRef create(PathSensitiveBugReport &Report) {
+    return new Tracker(Report);
+  }
+
   PathSensitiveBugReport &getReport() { return Report; }
 
   /// Describes a tracking result with the most basic information of what was
@@ -318,6 +328,18 @@
   Tracker &getParentTracker() { return ParentTracker; }
 };
 
+/// Visitor that tracks expressions and values.
+class TrackingBugReporterVisitor : public BugReporterVisitor {
+private:
+  TrackerRef ParentTracker;
+
+public:
+  TrackingBugReporterVisitor(TrackerRef ParentTracker)
+      : ParentTracker(ParentTracker) {}
+
+  Tracker &getParentTracker() { return *ParentTracker; }
+};
+
 /// Attempts to add visitors to track expression value back to its point of
 /// origin.
 ///
@@ -335,13 +357,31 @@
                           TrackingKind TKind = TrackingKind::Thorough,
                           bool EnableNullFPSuppression = true);
 
+/// Track how the value got stored into the given region and where it came
+/// from.
+///
+/// \param V We're searching for the store where \c R received this value.
+/// \param R The region we're tracking.
+/// \param Opts Tracking options specifying how we want to track the value.
+/// \param Origin Only adds notes when the last store happened in a
+///        different stackframe to this one. Disregarded if the tracking kind
+///        is thorough.
+///        This is useful, because for non-tracked regions, notes about
+///        changes to its value in a nested stackframe could be pruned, and
+///        this visitor can prevent that without polluting the bugpath too
+///        much.
+void trackStoredValue(SVal V, const MemRegion *R,
+                      PathSensitiveBugReport &Report, TrackingOptions Opts = {},
+                      const StackFrameContext *Origin = nullptr);
+
 const Expr *getDerefExpr(const Stmt *S);
 
 } // namespace bugreporter
 
 /// Finds last store into the given region,
 /// which is different from a given symbolic value.
-class FindLastStoreBRVisitor final : public BugReporterVisitor {
+class FindLastStoreBRVisitor final
+    : public bugreporter::TrackingBugReporterVisitor {
   const MemRegion *R;
   SVal V;
   bool Satisfied = false;
@@ -365,11 +405,13 @@
   ///        changes to its value in a nested stackframe could be pruned, and
   ///        this visitor can prevent that without polluting the bugpath too
   ///        much.
-  FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
-                         bool InEnableNullFPSuppression, TrackingKind TKind,
+  FindLastStoreBRVisitor(bugreporter::TrackerRef ParentTracker, KnownSVal V,
+                         const MemRegion *R, bool InEnableNullFPSuppression,
+                         TrackingKind TKind,
                          const StackFrameContext *OriginSFC = nullptr)
-      : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression),
-        TKind(TKind), OriginSFC(OriginSFC) {
+      : TrackingBugReporterVisitor(ParentTracker), R(R), V(V),
+        EnableNullFPSuppression(InEnableNullFPSuppression), TKind(TKind),
+        OriginSFC(OriginSFC) {
     assert(R);
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to