r179554 - [analyzer] Re-enable using global regions as a symbolic base.

Jordan Rose jordan_rose at apple.com
Mon Apr 15 13:39:45 PDT 2013


Author: jrose
Date: Mon Apr 15 15:39:45 2013
New Revision: 179554

URL: http://llvm.org/viewvc/llvm-project?rev=179554&view=rev
Log:
[analyzer] Re-enable using global regions as a symbolic base.

Now that we're invalidating global regions properly, we want to continue
taking advantage of a particular optimization: if all global regions are
invalidated together, we can represent the bindings of each region with
a "derived region value" symbol. Essentially, this lazily links each
global region with a single symbol created at invalidation time, rather
than binding each region with a new symbolic value.

We used to do this, but haven't been for a while; the previous commit
re-enabled this code path, and this handles the fallout.

<rdar://problem/13464044>

Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp
    cfe/trunk/test/Analysis/Inputs/system-header-simulator.h
    cfe/trunk/test/Analysis/global-region-invalidation.c
    cfe/trunk/test/Analysis/global_region_invalidation.mm

Modified: cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp?rev=179554&r1=179553&r2=179554&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/RegionStore.cpp Mon Apr 15 15:39:45 2013
@@ -490,8 +490,7 @@ public: // Part of public interface to c
 
   SVal getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
                                          const TypedValueRegion *R,
-                                         QualType Ty,
-                                         const MemRegion *superR);
+                                         QualType Ty);
   
   SVal getLazyBinding(const SubRegion *LazyBindingRegion,
                       RegionBindingsRef LazyBinding);
@@ -1546,7 +1545,7 @@ SVal RegionStoreManager::getBindingForEl
       }
     }
   }
-  return getBindingForFieldOrElementCommon(B, R, R->getElementType(),superR);
+  return getBindingForFieldOrElementCommon(B, R, R->getElementType());
 }
 
 SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
@@ -1557,7 +1556,7 @@ SVal RegionStoreManager::getBindingForFi
     return *V;
 
   QualType Ty = R->getValueType();
-  return getBindingForFieldOrElementCommon(B, R, Ty, R->getSuperRegion());
+  return getBindingForFieldOrElementCommon(B, R, Ty);
 }
 
 Optional<SVal>
@@ -1620,8 +1619,7 @@ SVal RegionStoreManager::getLazyBinding(
 SVal
 RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
                                                       const TypedValueRegion *R,
-                                                      QualType Ty,
-                                                      const MemRegion *superR) {
+                                                      QualType Ty) {
 
   // At this point we have already checked in either getBindingForElement or
   // getBindingForField if 'R' has a direct binding.
@@ -1654,8 +1652,9 @@ RegionStoreManager::getBindingForFieldOr
   // quickly result in a warning.
   bool hasPartialLazyBinding = false;
 
-  const SubRegion *Base = dyn_cast<SubRegion>(superR);
-  while (Base) {
+  const SubRegion *SR = dyn_cast<SubRegion>(R);
+  while (SR) {
+    const MemRegion *Base = SR->getSuperRegion();
     if (Optional<SVal> D = getBindingForDerivedDefaultValue(B, Base, R, Ty)) {
       if (D->getAs<nonloc::LazyCompoundVal>()) {
         hasPartialLazyBinding = true;
@@ -1673,7 +1672,7 @@ RegionStoreManager::getBindingForFieldOr
     
     // If our super region is a field or element itself, walk up the region
     // hierarchy to see if there is a default value installed in an ancestor.
-    Base = dyn_cast<SubRegion>(Base->getSuperRegion());
+    SR = dyn_cast<SubRegion>(Base);
   }
 
   if (R->hasStackNonParametersStorage()) {
@@ -1681,7 +1680,7 @@ RegionStoreManager::getBindingForFieldOr
       // Currently we don't reason specially about Clang-style vectors.  Check
       // if superR is a vector and if so return Unknown.
       if (const TypedValueRegion *typedSuperR = 
-            dyn_cast<TypedValueRegion>(superR)) {
+            dyn_cast<TypedValueRegion>(R->getSuperRegion())) {
         if (typedSuperR->getValueType()->isVectorType())
           return UnknownVal();
       }

Modified: cfe/trunk/test/Analysis/Inputs/system-header-simulator.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Inputs/system-header-simulator.h?rev=179554&r1=179553&r2=179554&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/Inputs/system-header-simulator.h (original)
+++ cfe/trunk/test/Analysis/Inputs/system-header-simulator.h Mon Apr 15 15:39:45 2013
@@ -5,6 +5,10 @@
 // suppressed.
 #pragma clang system_header
 
+#ifdef __cplusplus
+#define restrict /*restrict*/
+#endif
+
 typedef struct _FILE FILE;
 extern FILE *stdin;
 extern FILE *stdout;

Modified: cfe/trunk/test/Analysis/global-region-invalidation.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/global-region-invalidation.c?rev=179554&r1=179553&r2=179554&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/global-region-invalidation.c (original)
+++ cfe/trunk/test/Analysis/global-region-invalidation.c Mon Apr 15 15:39:45 2013
@@ -44,7 +44,10 @@ int testErrnoSystem() {
     fscanf(stdin, "%d", &i); // errno gets invalidated here.
     return 5 / errno; // no-warning
   }
-  return 0;
+
+  errno = 0;
+  fscanf(stdin, "%d", &i); // errno gets invalidated here.
+  return 5 / errno; // no-warning
 }
 
 // Test that errno gets invalidated by internal calls.

Modified: cfe/trunk/test/Analysis/global_region_invalidation.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/global_region_invalidation.mm?rev=179554&r1=179553&r2=179554&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/global_region_invalidation.mm (original)
+++ cfe/trunk/test/Analysis/global_region_invalidation.mm Mon Apr 15 15:39:45 2013
@@ -2,6 +2,8 @@
 
 void clang_analyzer_eval(int);
 
+#include "Inputs/system-header-simulator.h"
+
 void use(int);
 id foo(int x) {
   if (x)
@@ -19,9 +21,10 @@ void testGlobalRef() {
 }
 
 extern int globalInt;
-extern struct {
+struct IntWrapper {
   int value;
-} globalStruct;
+};
+extern struct IntWrapper globalStruct;
 extern void invalidateGlobals();
 
 void testGlobalInvalidation() {
@@ -38,6 +41,18 @@ void testGlobalInvalidation() {
   invalidateGlobals();
   clang_analyzer_eval(globalInt == 42); // expected-warning{{UNKNOWN}}
   clang_analyzer_eval(globalStruct.value == 43); // expected-warning{{UNKNOWN}}
+
+  // Repeat to make sure we don't get the /same/ new symbolic values.
+  if (globalInt != 42)
+    return;
+  if (globalStruct.value != 43)
+    return;
+  clang_analyzer_eval(globalInt == 42); // expected-warning{{TRUE}}
+  clang_analyzer_eval(globalStruct.value == 43); // expected-warning{{TRUE}}
+
+  invalidateGlobals();
+  clang_analyzer_eval(globalInt == 42); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(globalStruct.value == 43); // expected-warning{{UNKNOWN}}
 }
 
 void testGlobalInvalidationWithDirectBinding() {
@@ -53,3 +68,121 @@ void testGlobalInvalidationWithDirectBin
   clang_analyzer_eval(globalInt == 42); // expected-warning{{UNKNOWN}}
   clang_analyzer_eval(globalStruct.value == 43); // expected-warning{{UNKNOWN}}
 }
+
+void testStaticLocals(void) {
+  static int i;
+  int tmp;
+
+  extern int someSymbolicValue();
+  i = someSymbolicValue();
+
+  if (i == 5) {
+    clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
+    scanf("%d", &tmp);
+    clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
+    invalidateGlobals();
+    clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
+  }
+
+  i = 6;
+  clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
+  scanf("%d", &tmp);
+  clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
+  invalidateGlobals();
+  clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
+
+  i = someSymbolicValue();
+  if (i == 7) {
+    clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
+    scanf("%d", &i);
+    clang_analyzer_eval(i == 7); // expected-warning{{UNKNOWN}}
+  }
+
+  i = 8;
+  clang_analyzer_eval(i == 8); // expected-warning{{TRUE}}
+  scanf("%d", &i);
+  clang_analyzer_eval(i == 8); // expected-warning{{UNKNOWN}}
+}
+
+void testNonSystemGlobals(void) {
+  extern int i;
+  int tmp;
+
+  if (i == 5) {
+    clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
+    scanf("%d", &tmp);
+    clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
+    invalidateGlobals();
+    clang_analyzer_eval(i == 5); // expected-warning{{UNKNOWN}}
+  }
+
+  i = 6;
+  clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
+  scanf("%d", &tmp);
+  clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
+  invalidateGlobals();
+  clang_analyzer_eval(i == 6); // expected-warning{{UNKNOWN}}
+
+  if (i == 7) {
+    clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
+    scanf("%d", &i);
+    clang_analyzer_eval(i == 7); // expected-warning{{UNKNOWN}}
+  }
+
+  i = 8;
+  clang_analyzer_eval(i == 8); // expected-warning{{TRUE}}
+  scanf("%d", &i);
+  clang_analyzer_eval(i == 8); // expected-warning{{UNKNOWN}}
+}
+
+void testWrappedGlobals(void) {
+  extern char c;
+  SomeStruct s;
+
+  if (c == 'C') {
+    s.p = &c;
+    clang_analyzer_eval(c == 'C'); // expected-warning{{TRUE}}
+    fakeSystemHeaderCall(0);
+    clang_analyzer_eval(c == 'C'); // expected-warning{{TRUE}}
+    fakeSystemHeaderCall(&s);
+    clang_analyzer_eval(c == 'C'); // expected-warning{{UNKNOWN}}
+  }
+
+  c = 'c';
+  s.p = &c;
+  clang_analyzer_eval(c == 'c'); // expected-warning{{TRUE}}
+  fakeSystemHeaderCall(0);
+  clang_analyzer_eval(c == 'c'); // expected-warning{{TRUE}}
+  fakeSystemHeaderCall(&s);
+  clang_analyzer_eval(c == 'c'); // expected-warning{{UNKNOWN}}
+
+  if (c == 'C') {
+    s.p = &c;
+    clang_analyzer_eval(c == 'C'); // expected-warning{{TRUE}}
+    fakeSystemHeaderCall(0);
+    clang_analyzer_eval(c == 'C'); // expected-warning{{TRUE}}
+    fakeSystemHeaderCall(&s);
+    clang_analyzer_eval(c == 'C'); // expected-warning{{UNKNOWN}}
+  }
+}
+
+void testWrappedStaticsViaGlobal(void) {
+  static char c;
+  extern SomeStruct s;
+
+  extern char getSomeChar();
+  c = getSomeChar();
+
+  if (c == 'C') {
+    s.p = &c;
+    clang_analyzer_eval(c == 'C'); // expected-warning{{TRUE}}
+    invalidateGlobals();
+    clang_analyzer_eval(c == 'C'); // expected-warning{{UNKNOWN}}
+  }
+
+  c = 'c';
+  s.p = &c;
+  clang_analyzer_eval(c == 'c'); // expected-warning{{TRUE}}
+  invalidateGlobals();
+  clang_analyzer_eval(c == 'c'); // expected-warning{{UNKNOWN}}
+}





More information about the cfe-commits mailing list