]> granicus.if.org Git - clang/commitdiff
[analyzer] Improve performance of the SVal simplification mechanism.
authorArtem Dergachev <artem.dergachev@gmail.com>
Thu, 31 May 2018 17:22:38 +0000 (17:22 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Thu, 31 May 2018 17:22:38 +0000 (17:22 +0000)
When neither LHS nor RHS of a binary operator expression can be simplified,
return the original expression instead of re-evaluating the binary operator.

Such re-evaluation was causing recusrive re-simplification which caused
the algorithmic complexity to explode.

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@333670 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
test/Analysis/hangs.c [new file with mode: 0644]

index be414fa9ee9dd00fd881da354b06b8c5d40307ce..31300d69f2ff7f26ad2db032665bb194dc7e9d86 100644 (file)
@@ -367,6 +367,15 @@ public:
     return loc::ConcreteInt(BasicVals.getValue(integer));
   }
 
+  /// Make an SVal that represents the given symbol. This follows the convention
+  /// of representing Loc-type symbols (symbolic pointers and references)
+  /// as Loc values wrapping the symbol rather than as plain symbol values.
+  SVal makeSymbolVal(SymbolRef Sym) {
+    if (Loc::isLocType(Sym->getType()))
+      return makeLoc(Sym);
+    return nonloc::SymbolVal(Sym);
+  }
+
   /// Return a memory region for the 'this' object reference.
   loc::MemRegionVal getCXXThis(const CXXMethodDecl *D,
                                const StackFrameContext *SFC);
index 4171ebf136876f0a5cfa9fa5dafb2348519740f9..d26ea498f95a23411131850943d5d384960a21a9 100644 (file)
@@ -1222,6 +1222,10 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
     ProgramStateRef State;
     SValBuilder &SVB;
 
+    static bool isUnchanged(SymbolRef Sym, SVal Val) {
+      return Sym == Val.getAsSymbol();
+    }
+
   public:
     Simplifier(ProgramStateRef State)
         : State(State), SVB(State->getStateManager().getSValBuilder()) {}
@@ -1231,8 +1235,7 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
               SVB.getKnownValue(State, nonloc::SymbolVal(S)))
         return Loc::isLocType(S->getType()) ? (SVal)SVB.makeIntLocVal(*I)
                                             : (SVal)SVB.makeIntVal(*I);
-      return Loc::isLocType(S->getType()) ? (SVal)SVB.makeLoc(S) 
-                                          : nonloc::SymbolVal(S);
+      return SVB.makeSymbolVal(S);
     }
 
     // TODO: Support SymbolCast. Support IntSymExpr when/if we actually
@@ -1240,6 +1243,8 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
 
     SVal VisitSymIntExpr(const SymIntExpr *S) {
       SVal LHS = Visit(S->getLHS());
+      if (isUnchanged(S->getLHS(), LHS))
+        return SVB.makeSymbolVal(S);
       SVal RHS;
       // By looking at the APSInt in the right-hand side of S, we cannot
       // figure out if it should be treated as a Loc or as a NonLoc.
@@ -1264,6 +1269,8 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
     SVal VisitSymSymExpr(const SymSymExpr *S) {
       SVal LHS = Visit(S->getLHS());
       SVal RHS = Visit(S->getRHS());
+      if (isUnchanged(S->getLHS(), LHS) && isUnchanged(S->getRHS(), RHS))
+        return SVB.makeSymbolVal(S);
       return SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType());
     }
 
@@ -1274,13 +1281,20 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
     SVal VisitNonLocSymbolVal(nonloc::SymbolVal V) {
       // Simplification is much more costly than computing complexity.
       // For high complexity, it may be not worth it.
-      if (V.getSymbol()->computeComplexity() > 100)
-        return V;
       return Visit(V.getSymbol());
     }
 
     SVal VisitSVal(SVal V) { return V; }
   };
 
-  return Simplifier(State).Visit(V);
+  // A crude way of preventing this function from calling itself from evalBinOp.
+  static bool isReentering = false;
+  if (isReentering)
+    return V;
+
+  isReentering = true;
+  SVal SimplifiedV = Simplifier(State).Visit(V);
+  isReentering = false;
+
+  return SimplifiedV;
 }
diff --git a/test/Analysis/hangs.c b/test/Analysis/hangs.c
new file mode 100644 (file)
index 0000000..b109bcb
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker core -verify %s
+
+// expected-no-diagnostics
+
+// Stuff that used to hang.
+
+int g();
+
+int f(int y) {
+  return y + g();
+}
+
+int produce_a_very_large_symbol(int x) {
+  return f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(
+             f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(x))))))))))))))))))))))))))))))));
+}
+
+void produce_an_exponentially_exploding_symbol(int x, int y) {
+  x += y; y += x + g();
+  x += y; y += x + g();
+  x += y; y += x + g();
+  x += y; y += x + g();
+  x += y; y += x + g();
+  x += y; y += x + g();
+  x += y; y += x + g();
+  x += y; y += x + g();
+  x += y; y += x + g();
+  x += y; y += x + g();
+  x += y; y += x + g();
+}