[clang] [analyzer] Reduce constraint on modulo with small concrete range (PR #65448)

Ding Fei via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 6 00:28:12 PDT 2023


https://github.com/danix800 created https://github.com/llvm/llvm-project/pull/65448:

Fixes #54377

>From 2b04f714f1e1985546ff7ed00c131591316782b8 Mon Sep 17 00:00:00 2001
From: dingfei <fding at feysh.com>
Date: Wed, 6 Sep 2023 10:03:21 +0800
Subject: [PATCH] [analyzer] Reduce constraint on modulo with small concrete
 range

---
 .../PathSensitive/RangedConstraintManager.h   |  1 +
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp  |  3 +
 .../Core/RangeConstraintManager.cpp           | 48 +++++++++++++++
 .../Core/RangedConstraintManager.cpp          | 14 +++++
 clang/test/Analysis/constraint-assignor.c     | 60 +++++++++++++++++++
 5 files changed, 126 insertions(+)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
index 49ea006e27aa54..f350cfa1cd011c 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -476,6 +476,7 @@ class RangedConstraintManager : public SimpleConstraintManager {
   //===------------------------------------------------------------------===//
 private:
   static void computeAdjustment(SymbolRef &Sym, llvm::APSInt &Adjustment);
+  static void computeScaling(SymbolRef &Sym, llvm::APSInt &ConvertedInt);
 };
 
 /// Try to simplify a given symbolic expression based on the constraints in
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 0e2ac78f7089c5..670de6795f1c2d 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1702,6 +1702,9 @@ ProgramStateRef ExprEngine::escapeValues(ProgramStateRef State,
 
 void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
                        ExplodedNodeSet &DstTop) {
+  //  static int Count = 0;
+  //  llvm::errs() << "Count: " << Count++ << "\n";
+  //  S->dump();
   PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
                                 S->getBeginLoc(), "Error evaluating statement");
   ExplodedNodeSet Dst;
diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 5de99384449a4c..9bda29c87f3c0f 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -2073,6 +2073,14 @@ class ConstraintAssignor : public ConstraintAssignorBase<ConstraintAssignor> {
     if (Sym->getOpcode() != BO_Rem)
       return true;
     // a % b != 0 implies that a != 0.
+    // Z3 verification:
+    //   (declare-const a Int)
+    //   (declare-const m Int)
+    //   (assert (not (= m 0)))
+    //   (assert (not (= (mod a m) 0)))
+    //   (assert (= a 0))
+    //   (check-sat)
+    //   ; unsat
     if (!Constraint.containsZero()) {
       SVal SymSVal = Builder.makeSymbolVal(Sym->getLHS());
       if (auto NonLocSymSVal = SymSVal.getAs<nonloc::SymbolVal>()) {
@@ -2080,6 +2088,46 @@ class ConstraintAssignor : public ConstraintAssignorBase<ConstraintAssignor> {
         if (!State)
           return false;
       }
+    } else if (auto *SIE = dyn_cast<SymIntExpr>(Sym);
+               SIE && Constraint.encodesFalseRange()) {
+      // a % m == 0 && a in [x, y] && y - x < m implies that
+      // a = (y < 0 ? x : y) / m * m which is a 'ConcreteInt'
+      // where x and m are 'ConcreteInt'.
+      //
+      // Z3 verification:
+      //   (declare-const a Int)
+      //   (declare-const m Int)
+      //   (declare-const x Int)
+      //   (declare-const y Int)
+      //   (assert (= (mod a m) 0))
+      //   (assert (< (- y x) m))
+      //   (assert (and (>= a x) (<= a y)))
+      //   (assert (not (= a (* (div y m) m))))
+      //   (check-sat)
+      //   ; unsat
+      llvm::APSInt Modulo = SIE->getRHS();
+      Modulo = llvm::APSInt(Modulo.abs(), Modulo.isUnsigned());
+      RangeSet RS =
+          SymbolicRangeInferrer::inferRange(RangeFactory, State, SIE->getLHS());
+      if (RS.size() == 1) {
+        auto R = RS.begin();
+        if ((R->To() - R->From()).getExtValue() < Modulo.getExtValue()) {
+          SVal SymSVal = Builder.makeSymbolVal(SIE->getLHS());
+          if (auto NonLocSymSVal = SymSVal.getAs<nonloc::SymbolVal>()) {
+            auto NewConstConstraint = Builder.makeIntVal(
+                (R->To() > 0 ? R->To() : R->From()) / Modulo * Modulo);
+            if (auto Cond = Builder
+                                .evalBinOp(State, BO_EQ, *NonLocSymSVal,
+                                           NewConstConstraint,
+                                           Builder.getConditionType())
+                                .template getAs<DefinedOrUnknownSVal>()) {
+              State = State->assume(*Cond, true);
+              if (!State)
+                return false;
+            }
+          }
+        }
+      }
     }
     return true;
   }
diff --git a/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
index 4bbe933be2129e..682c006acc4e7e 100644
--- a/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
@@ -184,6 +184,7 @@ ProgramStateRef RangedConstraintManager::assumeSymRel(ProgramStateRef State,
   // Convert the right-hand side integer as necessary.
   APSIntType ComparisonType = std::max(WraparoundType, APSIntType(Int));
   llvm::APSInt ConvertedInt = ComparisonType.convert(Int);
+  //  computeScaling(Sym, ConvertedInt);
 
   // Prefer unsigned comparisons.
   if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
@@ -232,6 +233,19 @@ void RangedConstraintManager::computeAdjustment(SymbolRef &Sym,
   }
 }
 
+void RangedConstraintManager::computeScaling(SymbolRef &Sym,
+                                             llvm::APSInt &ConvertedInt) {
+  if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(Sym)) {
+    BinaryOperator::Opcode Op = SE->getOpcode();
+    if (Op == BO_Div) {
+      Sym = SE->getLHS();
+      auto &RHS = SE->getRHS();
+      ConvertedInt =
+          ConvertedInt * APSIntType(ConvertedInt).convert(SE->getRHS());
+    }
+  }
+}
+
 SVal simplifyToSVal(ProgramStateRef State, SymbolRef Sym) {
   SValBuilder &SVB = State->getStateManager().getSValBuilder();
   return SVB.simplifySVal(State, SVB.makeSymbolVal(Sym));
diff --git a/clang/test/Analysis/constraint-assignor.c b/clang/test/Analysis/constraint-assignor.c
index 8210e576c98bd2..150fe20c9f37a0 100644
--- a/clang/test/Analysis/constraint-assignor.c
+++ b/clang/test/Analysis/constraint-assignor.c
@@ -5,6 +5,7 @@
 
 void clang_analyzer_warnIfReached(void);
 void clang_analyzer_eval(int);
+void clang_analyzer_dump(int);
 
 void rem_constant_rhs_ne_zero(int x, int y) {
   if (x % 3 == 0) // x % 3 != 0 -> x != 0
@@ -82,3 +83,62 @@ void remainder_with_adjustment_of_composit_lhs(int x, int y) {
   clang_analyzer_eval(x + y != -1);    // expected-warning{{TRUE}}
   (void)(x * y); // keep the constraints alive.
 }
+
+void remainder_infeasible(int x, int y) {
+  if (x <= 2 || x >= 5)
+    return;
+  if (x % 5 != 0)
+    return;
+  clang_analyzer_warnIfReached(); // no-warning
+  (void)x; // keep the constraints alive.
+}
+
+void remainder_within_modulo_positive_range_unsigned(unsigned x) {
+  if (x <= 2 || x > 6)
+    return;
+  clang_analyzer_dump(x); // expected-warning{{reg_$0<unsigned int x>}}
+  if (x % 5 != 0)
+    return;
+  clang_analyzer_dump(x);          // expected-warning{{5 S32b}}
+  (void)x; // keep the constraints alive.
+}
+
+void remainder_within_modulo_positive_range(int x) {
+  if (x <= 2 || x > 6)
+    return;
+  clang_analyzer_dump(x); // expected-warning{{reg_$0<int x>}}
+  if (x % 5 != 0)
+    return;
+  clang_analyzer_dump(x);          // expected-warning{{5 S32b}}
+  (void)x; // keep the constraints alive.
+}
+
+void remainder_within_modulo_range_spans_zero(int x) {
+  if (x <= -2 || x > 2)
+    return;
+  clang_analyzer_dump(x); // expected-warning{{reg_$0<int x>}}
+  if (x % 5 != 0)
+    return;
+  clang_analyzer_dump(x);          // expected-warning{{0 S32b}}
+  (void)x; // keep the constraints alive.
+}
+
+void remainder_within_modulo_negative_range(int x) {
+  if (x <= -7 || x > -2)
+    return;
+  clang_analyzer_dump(x); // expected-warning{{reg_$0<int x>}}
+  if (x % 5 != 0)
+    return;
+  clang_analyzer_dump(x);          // expected-warning{{-5 S32b}}
+  (void)x; // keep the constraints alive.
+}
+
+void remainder_within_modulo_range_neg_mod(int x) {
+  if (x <= 2 || x > 6)
+    return;
+  clang_analyzer_dump(x); // expected-warning{{reg_$0<int x>}}
+  if (x % -5 != 0)
+    return;
+  clang_analyzer_dump(x);          // expected-warning{{5 S32b}}
+  (void)x; // keep the constraints alive.
+}



More information about the cfe-commits mailing list