[clang] 0a17896 - [Analyzer][Core] Make SValBuilder to better simplify svals with 3 symbols in the tree

Gabor Marton via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 30 02:27:33 PST 2021


Author: Gabor Marton
Date: 2021-11-30T11:24:59+01:00
New Revision: 0a17896fe6fdbbde1f9d3ffbb10a4f3bfa8960f9

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

LOG: [Analyzer][Core] Make SValBuilder to better simplify svals with 3 symbols in the tree

Add the capability to simplify more complex constraints where there are 3
symbols in the tree. In this change I extend simplifySVal to query constraints
of children sub-symbols in a symbol tree. (The constraint for the parent is
asked in getKnownValue.)

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

Added: 
    clang/test/Analysis/svalbuilder-simplify-compound-svals.cpp

Modified: 
    clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
    clang/test/Analysis/taint-tester.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index e179ecc33481..4ca35dd06ae5 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -1102,7 +1102,6 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
   if (SymbolRef Sym = V.getAsSymbol())
     return state->getConstraintManager().getSymVal(state, Sym);
 
-  // FIXME: Add support for SymExprs.
   return nullptr;
 }
 
@@ -1134,6 +1133,24 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
       return cache(Sym, SVB.makeSymbolVal(Sym));
     }
 
+    // Return the known const value for the Sym if available, or return Undef
+    // otherwise.
+    SVal getConst(SymbolRef Sym) {
+      const llvm::APSInt *Const =
+          State->getConstraintManager().getSymVal(State, Sym);
+      if (Const)
+        return Loc::isLocType(Sym->getType()) ? (SVal)SVB.makeIntLocVal(*Const)
+                                              : (SVal)SVB.makeIntVal(*Const);
+      return UndefinedVal();
+    }
+
+    SVal getConstOrVisit(SymbolRef Sym) {
+      const SVal Ret = getConst(Sym);
+      if (Ret.isUndef())
+        return Visit(Sym);
+      return Ret;
+    }
+
   public:
     Simplifier(ProgramStateRef State)
         : State(State), SVB(State->getStateManager().getSValBuilder()) {}
@@ -1147,15 +1164,14 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
       return SVB.makeSymbolVal(S);
     }
 
-    // TODO: Support SymbolCast. Support IntSymExpr when/if we actually
-    // start producing them.
+    // TODO: Support SymbolCast.
 
     SVal VisitSymIntExpr(const SymIntExpr *S) {
       auto I = Cached.find(S);
       if (I != Cached.end())
         return I->second;
 
-      SVal LHS = Visit(S->getLHS());
+      SVal LHS = getConstOrVisit(S->getLHS());
       if (isUnchanged(S->getLHS(), LHS))
         return skip(S);
 
@@ -1187,9 +1203,10 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
       if (I != Cached.end())
         return I->second;
 
-      SVal RHS = Visit(S->getRHS());
+      SVal RHS = getConstOrVisit(S->getRHS());
       if (isUnchanged(S->getRHS(), RHS))
         return skip(S);
+
       SVal LHS = SVB.makeIntVal(S->getLHS());
       return cache(
           S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType()));
@@ -1208,8 +1225,9 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
           Loc::isLocType(S->getRHS()->getType()))
         return skip(S);
 
-      SVal LHS = Visit(S->getLHS());
-      SVal RHS = Visit(S->getRHS());
+      SVal LHS = getConstOrVisit(S->getLHS());
+      SVal RHS = getConstOrVisit(S->getRHS());
+
       if (isUnchanged(S->getLHS(), LHS) && isUnchanged(S->getRHS(), RHS))
         return skip(S);
 

diff  --git a/clang/test/Analysis/svalbuilder-simplify-compound-svals.cpp b/clang/test/Analysis/svalbuilder-simplify-compound-svals.cpp
new file mode 100644
index 000000000000..0417507476ee
--- /dev/null
+++ b/clang/test/Analysis/svalbuilder-simplify-compound-svals.cpp
@@ -0,0 +1,76 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=debug.ExprInspection \
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -verify
+
+// Here we test whether the SValBuilder is capable to simplify existing
+// compound SVals (where there are at leaset 3 symbols in the tree) based on
+// newly added constraints.
+
+void clang_analyzer_eval(bool);
+void clang_analyzer_warnIfReached();
+
+void test_left_tree_constrained(int x, int y, int z) {
+  if (x + y + z != 0)
+    return;
+  if (x + y != 0)
+    return;
+  clang_analyzer_eval(x + y + z == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(x + y == 0);     // expected-warning{{TRUE}}
+  clang_analyzer_eval(z == 0);         // expected-warning{{TRUE}}
+  x = y = z = 1;
+  return;
+}
+
+void test_right_tree_constrained(int x, int y, int z) {
+  if (x + y * z != 0)
+    return;
+  if (y * z != 0)
+    return;
+  clang_analyzer_eval(x + y * z == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(y * z == 0);     // expected-warning{{TRUE}}
+  clang_analyzer_eval(x == 0);         // expected-warning{{TRUE}}
+  return;
+}
+
+void test_left_tree_constrained_minus(int x, int y, int z) {
+  if (x - y - z != 0)
+    return;
+  if (x - y != 0)
+    return;
+  clang_analyzer_eval(x - y - z == 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(x - y == 0);     // expected-warning{{TRUE}}
+  clang_analyzer_eval(z == 0);         // expected-warning{{TRUE}}
+  x = y = z = 1;
+  return;
+}
+
+void test_SymInt_constrained(int x, int y, int z) {
+  if (x * y * z != 4)
+    return;
+  if (z != 2)
+    return;
+  if (x * y == 3) {
+    clang_analyzer_warnIfReached();     // no-warning
+    return;
+  }
+  (void)(x * y * z);
+}
+
+void test_SValBuilder_simplifies_IntSym(int x, int y, int z) {
+  // Most IntSym BinOps are transformed to SymInt in SimpleSValBuilder.
+  // Division is one exception.
+  x = 77 / (y + z);
+  if (y + z != 1)
+    return;
+  clang_analyzer_eval(x == 77);         // expected-warning{{TRUE}}
+  (void)(x * y * z);
+}
+
+void recurring_symbol(int b) {
+  if (b * b != b)
+    if ((b * b) * b * b != (b * b) * b)
+      if (b * b == 1)                   // no-crash (assert should not fire)
+        clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}

diff  --git a/clang/test/Analysis/taint-tester.c b/clang/test/Analysis/taint-tester.c
index 3a8cc1825a02..cbb2ad6c9744 100644
--- a/clang/test/Analysis/taint-tester.c
+++ b/clang/test/Analysis/taint-tester.c
@@ -59,7 +59,7 @@ void taintTracking(int x) {
   int tty = xy.y; // expected-warning + {{tainted}}
 }
 
-void BitwiseOp(int in, char inn) {
+void BitwiseOp(int in, char inn, int zz) {
   // Taint on bitwise operations, integer to integer cast.
   int m;
   int x = 0;
@@ -67,11 +67,12 @@ void BitwiseOp(int in, char inn) {
   int y = (in << (x << in)) * 5;// expected-warning + {{tainted}}
   // The next line tests integer to integer cast.
   int z = y & inn; // expected-warning + {{tainted}}
-  if (y == 5) // expected-warning + {{tainted}}
+  if (y == zz) { // expected-warning + {{tainted}}
     m = z | z;// expected-warning + {{tainted}}
+  }
   else
     m = inn;
-  int mm = m; // expected-warning + {{tainted}}
+  int mm = m; // expected-warning 1 {{tainted}}
 }
 
 // Test getenv.


        


More information about the cfe-commits mailing list