r175194 - [analyzer] Try constant-evaluation for all variables, not just globals.

Jordan Rose jordan_rose at apple.com
Thu Feb 14 11:06:11 PST 2013


Author: jrose
Date: Thu Feb 14 13:06:11 2013
New Revision: 175194

URL: http://llvm.org/viewvc/llvm-project?rev=175194&view=rev
Log:
[analyzer] Try constant-evaluation for all variables, not just globals.

In C++, constants captured by lambdas (and blocks) are not actually stored
in the closure object, since they can be expanded at compile time. In this
case, they will have no binding when we go to look them up. Previously,
RegionStore thought they were uninitialized stack variables; now, it checks
to see if they are a constant we know how to evaluate, using the same logic
as r175026.

This particular code path is only for scalar variables. Constant arrays and
structs are still unfortunately unhandled; we'll need a stronger solution
for those.

This may have a small performance impact, but only for truly-undefined
local variables, captures in a non-inlined block, and non-constant globals.
Even then, in the non-constant case we're only doing a quick type check.

<rdar://problem/13105553>

Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp
    cfe/trunk/test/Analysis/blocks-no-inline.c

Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp?rev=175194&r1=175193&r2=175194&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Thu Feb 14 13:06:11 2013
@@ -1497,6 +1497,26 @@ SVal RegionStoreManager::getBindingForOb
   return getBindingForLazySymbol(R);
 }
 
+static Optional<SVal> getConstValue(SValBuilder &SVB, const VarDecl *VD) {
+  ASTContext &Ctx = SVB.getContext();
+  if (!VD->getType().isConstQualified())
+    return Optional<SVal>();
+
+  const Expr *Init = VD->getInit();
+  if (!Init)
+    return Optional<SVal>();
+
+  llvm::APSInt Result;
+  if (Init->EvaluateAsInt(Result, Ctx))
+    return SVB.makeIntVal(Result);
+
+  if (Init->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
+    return SVB.makeNull();
+
+  // FIXME: Handle other possible constant expressions.
+  return Optional<SVal>();
+}
+
 SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
                                           const VarRegion *R) {
 
@@ -1506,37 +1526,30 @@ SVal RegionStoreManager::getBindingForVa
 
   // Lazily derive a value for the VarRegion.
   const VarDecl *VD = R->getDecl();
-  QualType T = VD->getType();
   const MemSpaceRegion *MS = R->getMemorySpace();
 
-  if (isa<UnknownSpaceRegion>(MS) ||
-      isa<StackArgumentsSpaceRegion>(MS))
+  // Arguments are always symbolic.
+  if (isa<StackArgumentsSpaceRegion>(MS))
+    return svalBuilder.getRegionValueSymbolVal(R);
+
+  // Is 'VD' declared constant?  If so, retrieve the constant value.
+  if (Optional<SVal> V = getConstValue(svalBuilder, VD))
+    return *V;
+
+  // This must come after the check for constants because closure-captured
+  // constant variables may appear in UnknownSpaceRegion.
+  if (isa<UnknownSpaceRegion>(MS))
     return svalBuilder.getRegionValueSymbolVal(R);
 
   if (isa<GlobalsSpaceRegion>(MS)) {
+    QualType T = VD->getType();
+
     // Function-scoped static variables are default-initialized to 0; if they
     // have an initializer, it would have been processed by now.
     if (isa<StaticGlobalSpaceRegion>(MS))
       return svalBuilder.makeZeroVal(T);
 
-    // Other globals 
-    // Is 'VD' declared constant?  If so, retrieve the constant value.
-    QualType CT = Ctx.getCanonicalType(T);
-    if (CT.isConstQualified()) {
-      if (const Expr *Init = VD->getInit()) {
-        llvm::APSInt Result;
-        if (Init->EvaluateAsInt(Result, Ctx))
-          return svalBuilder.makeIntVal(Result);
-
-        if (Init->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
-          return svalBuilder.makeNull();
-
-        // FIXME: Handle other possible constant expressions.
-      }
-    }
-
-    if (const Optional<SVal> &V
-          = getBindingForDerivedDefaultValue(B, MS, R, CT))
+    if (Optional<SVal> V = getBindingForDerivedDefaultValue(B, MS, R, T))
       return V.getValue();
 
     return svalBuilder.getRegionValueSymbolVal(R);

Modified: cfe/trunk/test/Analysis/blocks-no-inline.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/blocks-no-inline.c?rev=175194&r1=175193&r2=175194&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/blocks-no-inline.c (original)
+++ cfe/trunk/test/Analysis/blocks-no-inline.c Thu Feb 14 13:06:11 2013
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -fblocks -verify -x c++ %s
 
 void clang_analyzer_eval(int);
 
@@ -11,3 +12,29 @@ void testInvalidation() {
   // Under inlining, we will know that i == 1.
   clang_analyzer_eval(i == 0); // expected-warning{{UNKNOWN}}
 }
+
+
+const int globalConstant = 1;
+void testCapturedConstants() {
+  const int localConstant = 2;
+  static const int staticConstant = 3;
+
+  ^{
+    clang_analyzer_eval(globalConstant == 1); // expected-warning{{TRUE}}
+    clang_analyzer_eval(localConstant == 2); // expected-warning{{TRUE}}
+    clang_analyzer_eval(staticConstant == 3); // expected-warning{{TRUE}}
+  }();
+}
+
+typedef const int constInt;
+constInt anotherGlobalConstant = 1;
+void testCapturedConstantsTypedef() {
+  constInt localConstant = 2;
+  static constInt staticConstant = 3;
+
+  ^{
+    clang_analyzer_eval(anotherGlobalConstant == 1); // expected-warning{{TRUE}}
+    clang_analyzer_eval(localConstant == 2); // expected-warning{{TRUE}}
+    clang_analyzer_eval(staticConstant == 3); // expected-warning{{TRUE}}
+  }();
+}





More information about the cfe-commits mailing list