[clang] 160798a - [analyzer] Handle SymbolCast in SValBuilder

Gabor Marton via cfe-commits cfe-commits at lists.llvm.org
Tue May 31 23:42:16 PDT 2022


Author: Gabor Marton
Date: 2022-06-01T08:42:04+02:00
New Revision: 160798ab9be87a9be323966c5f5816a5b7ca818f

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

LOG: [analyzer] Handle SymbolCast in SValBuilder

Make the SimpleSValBuilder to be able to look up and use a constraint
for an operand of a SymbolCast, when the operand is constrained to a
const value.
This part of the SValBuilder is responsible for constant folding. We
need this constant folding, so the engine can work with less symbols,
this way it can be more efficient. Whenever a symbol is constrained with
a constant then we substitute the symbol with the corresponding integer.
If a symbol is constrained with a range, then the symbol is kept and we
fall-back to use the range based constraint manager, which is not that
efficient. This patch is the natural extension of the existing constant
folding machinery with the support of SymbolCast symbols.

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

Added: 
    clang/test/Analysis/svalbuilder-casts.cpp

Modified: 
    clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 1b0c377aedc2c..1232dcc40c522 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -1278,8 +1278,6 @@ SVal SimpleSValBuilder::simplifySValOnce(ProgramStateRef State, SVal V) {
       return SVB.makeSymbolVal(S);
     }
 
-    // TODO: Support SymbolCast.
-
     SVal VisitSymIntExpr(const SymIntExpr *S) {
       auto I = Cached.find(S);
       if (I != Cached.end())
@@ -1349,7 +1347,17 @@ SVal SimpleSValBuilder::simplifySValOnce(ProgramStateRef State, SVal V) {
           S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType()));
     }
 
-    // FIXME add VisitSymbolCast
+    SVal VisitSymbolCast(const SymbolCast *S) {
+      auto I = Cached.find(S);
+      if (I != Cached.end())
+        return I->second;
+      const SymExpr *OpSym = S->getOperand();
+      SVal OpVal = getConstOrVisit(OpSym);
+      if (isUnchanged(OpSym, OpVal))
+        return skip(S);
+
+      return cache(S, SVB.evalCast(OpVal, S->getType(), OpSym->getType()));
+    }
 
     SVal VisitUnarySymExpr(const UnarySymExpr *S) {
       auto I = Cached.find(S);

diff  --git a/clang/test/Analysis/svalbuilder-casts.cpp b/clang/test/Analysis/svalbuilder-casts.cpp
new file mode 100644
index 0000000000000..4cee98927a2ce
--- /dev/null
+++ b/clang/test/Analysis/svalbuilder-casts.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=debug.ExprInspection \
+// RUN:   -analyzer-config support-symbolic-integer-casts=true \
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -triple x86_64-unknown-linux-gnu \
+// RUN:   -verify
+
+// Test that the SValBuilder is able to look up and use a constraint for an
+// operand of a SymbolCast, when the operand is constrained to a const value.
+
+void clang_analyzer_eval(bool);
+
+extern void abort() __attribute__((__noreturn__));
+#define assert(expr) ((expr) ? (void)(0) : abort())
+
+void test(int x) {
+  // Constrain a SymSymExpr to a constant value.
+  assert(x * x == 1);
+  // It is expected to be able to get the constraint for the operand of the
+  // cast.
+  clang_analyzer_eval((char)(x * x) == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval((long)(x * x) == 1); // expected-warning{{TRUE}}
+}
+
+void test1(int x, int y) {
+  // Even if two lower bytes of `x` equal to zero, it doesn't mean that
+  // the entire `x` is zero. We are not able to know the exact value of x.
+  // It can be one of  65536 possible values like
+  // [0, 65536, -65536, 131072, -131072, ...]. To avoid huge range sets we
+  // still assume `x` in the range [INT_MIN, INT_MAX].
+  assert((short)x == 0); // Lower two bytes are set to 0.
+
+  static_assert((short)65536 == 0, "");
+  static_assert((short)-65536 == 0, "");
+  static_assert((short)131072 == 0, "");
+  static_assert((short)-131072 == 0, "");
+  clang_analyzer_eval(x == 0);       // expected-warning{{UNKNOWN}}
+
+  // These are not truncated to short as zero.
+  static_assert((short)1 != 0, "");
+  clang_analyzer_eval(x == 1);       // expected-warning{{FALSE}}
+  static_assert((short)-1 != 0, "");
+  clang_analyzer_eval(x == -1);      // expected-warning{{FALSE}}
+  static_assert((short)65537 != 0, "");
+  clang_analyzer_eval(x == 65537);   // expected-warning{{FALSE}}
+  static_assert((short)-65537 != 0, "");
+  clang_analyzer_eval(x == -65537);  // expected-warning{{FALSE}}
+  static_assert((short)131073 != 0, "");
+  clang_analyzer_eval(x == 131073);  // expected-warning{{FALSE}}
+  static_assert((short)-131073 != 0, "");
+  clang_analyzer_eval(x == -131073); // expected-warning{{FALSE}}
+
+  // Check for implicit cast.
+  short s = y;
+  assert(s == 0);
+  clang_analyzer_eval(y == 0); // expected-warning{{UNKNOWN}}
+}


        


More information about the cfe-commits mailing list