[clang] ca3d962 - [analyzer] Return from reAssume if State is posteriorly overconstrained

Gabor Marton via cfe-commits cfe-commits at lists.llvm.org
Thu May 26 04:51:15 PDT 2022


Author: Gabor Marton
Date: 2022-05-26T13:50:40+02:00
New Revision: ca3d962548b9699d69157d102e071607d27ba126

URL: https://github.com/llvm/llvm-project/commit/ca3d962548b9699d69157d102e071607d27ba126
DIFF: https://github.com/llvm/llvm-project/commit/ca3d962548b9699d69157d102e071607d27ba126.diff

LOG: [analyzer] Return from reAssume if State is posteriorly overconstrained

Depends on D124758. That patch introduced serious regression in the run-time in
some special cases. This fixes that.

Differential Revision: https://reviews.llvm.org/D126406

Added: 
    clang/test/Analysis/runtime-regression.c

Modified: 
    clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
    clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index cb6540ff7e7c4..f36ba70babc71 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -55,6 +55,8 @@ template <typename T> struct ProgramStateTrait {
   }
 };
 
+class RangeSet;
+
 /// \class ProgramState
 /// ProgramState - This class encapsulates:
 ///
@@ -79,7 +81,6 @@ class ProgramState : public llvm::FoldingSetNode {
   friend class ExplodedGraph;
   friend class ExplodedNode;
   friend class NodeBuilder;
-  friend class ConstraintManager;
 
   ProgramStateManager *stateMgr;
   Environment Env;           // Maps a Stmt to its current SVal.
@@ -113,6 +114,16 @@ class ProgramState : public llvm::FoldingSetNode {
   // posteriorly over-constrained. These parents are handled with special care:
   // we do not allow transitions to exploded nodes with such states.
   bool PosteriorlyOverconstrained = false;
+  // Make internal constraint solver entities friends so they can access the
+  // overconstrained-related functions. We want to keep this API inaccessible
+  // for Checkers.
+  friend class ConstraintManager;
+  friend ProgramStateRef reAssume(ProgramStateRef State,
+                                  const RangeSet *Constraint, SVal TheValue);
+  bool isPosteriorlyOverconstrained() const {
+    return PosteriorlyOverconstrained;
+  }
+  ProgramStateRef cloneAsPosteriorlyOverconstrained() const;
 
   unsigned refCount;
 
@@ -122,11 +133,6 @@ class ProgramState : public llvm::FoldingSetNode {
 
   void setStore(const StoreRef &storeRef);
 
-  ProgramStateRef cloneAsPosteriorlyOverconstrained() const;
-  bool isPosteriorlyOverconstrained() const {
-    return PosteriorlyOverconstrained;
-  }
-
 public:
   /// This ctor is used when creating the first ProgramState object.
   ProgramState(ProgramStateManager *mgr, const Environment& env,

diff  --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index e0ceac51d14f3..3d8d8aeafaec6 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -2530,10 +2530,19 @@ EquivalenceClass::removeMember(ProgramStateRef State, const SymbolRef Old) {
   return State;
 }
 
+// We must declare reAssume in clang::ento, otherwise we could not declare that
+// as a friend in ProgramState. More precisely, the call of reAssume would be
+// ambiguous (one in the global namespace and an other which is declared in
+// ProgramState is in clang::ento).
+namespace clang {
+namespace ento {
 // Re-evaluate an SVal with top-level `State->assume` logic.
 LLVM_NODISCARD ProgramStateRef reAssume(ProgramStateRef State,
                                         const RangeSet *Constraint,
                                         SVal TheValue) {
+  assert(State);
+  if (State->isPosteriorlyOverconstrained())
+    return nullptr;
   if (!Constraint)
     return State;
 
@@ -2556,6 +2565,8 @@ LLVM_NODISCARD ProgramStateRef reAssume(ProgramStateRef State,
   return State->assumeInclusiveRange(DefinedVal, Constraint->getMinValue(),
                                      Constraint->getMaxValue(), true);
 }
+} // namespace ento
+} // namespace clang
 
 // Iterate over all symbols and try to simplify them. Once a symbol is
 // simplified then we check if we can merge the simplified symbol's equivalence

diff  --git a/clang/test/Analysis/runtime-regression.c b/clang/test/Analysis/runtime-regression.c
new file mode 100644
index 0000000000000..55988e9df5ee0
--- /dev/null
+++ b/clang/test/Analysis/runtime-regression.c
@@ -0,0 +1,55 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:   -analyzer-checker=core,alpha.security.ArrayBoundV2 \
+// RUN:   -analyzer-checker=debug.ExprInspection \
+// RUN:   -triple x86_64-unknown-linux-gnu \
+// RUN:   -verify
+
+// This test is here to check if there is no significant run-time regression
+// related to the assume machinery. The analysis should finish in less than 10
+// seconds.
+
+// expected-no-diagnostics
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint64_t;
+
+int filter_slice_word(int sat_linesize, int sigma, int radius, uint64_t *sat,
+                      uint64_t *square_sat, int width, int height,
+                      int src_linesize, int dst_linesize, const uint16_t *src,
+                      uint16_t *dst, int jobnr, int nb_jobs) {
+  const int starty = height * jobnr / nb_jobs;
+  const int endy = height * (jobnr + 1) / nb_jobs;
+
+  for (int y = starty; y < endy; y++) {
+
+    int lower_y = y - radius < 0 ? 0 : y - radius;
+    int higher_y = y + radius + 1 > height ? height : y + radius + 1;
+    int dist_y = higher_y - lower_y;
+
+    for (int x = 0; x < width; x++) {
+
+      int lower_x = x - radius < 0 ? 0 : x - radius;
+      int higher_x = x + radius + 1 > width ? width : x + radius + 1;
+      int count = dist_y * (higher_x - lower_x);
+
+      // The below hunk caused significant regression in run-time.
+#if 1
+      uint64_t sum = sat[higher_y * sat_linesize + higher_x] -
+                     sat[higher_y * sat_linesize + lower_x] -
+                     sat[lower_y * sat_linesize + higher_x] +
+                     sat[lower_y * sat_linesize + lower_x];
+      uint64_t square_sum = square_sat[higher_y * sat_linesize + higher_x] -
+                            square_sat[higher_y * sat_linesize + lower_x] -
+                            square_sat[lower_y * sat_linesize + higher_x] +
+                            square_sat[lower_y * sat_linesize + lower_x];
+      uint64_t mean = sum / count;
+      uint64_t var = (square_sum - sum * sum / count) / count;
+      dst[y * dst_linesize + x] =
+          (sigma * mean + var * src[y * src_linesize + x]) / (sigma + var);
+#endif
+
+    }
+  }
+  return 0;
+}


        


More information about the cfe-commits mailing list