]> granicus.if.org Git - clang/commitdiff
[analyzer] Re-enable using global regions as a symbolic base.
authorJordan Rose <jordan_rose@apple.com>
Mon, 15 Apr 2013 20:39:45 +0000 (20:39 +0000)
committerJordan Rose <jordan_rose@apple.com>
Mon, 15 Apr 2013 20:39:45 +0000 (20:39 +0000)
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>

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

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

index 09ee549ebb41b56d24b93456e3ff4159baf2f60d..eeaf51d8ee0eebef2ecf032556ceef0c9bc88912 100644 (file)
@@ -490,8 +490,7 @@ public: // Part of public interface to class.
 
   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::getBindingForElement(RegionBindingsConstRef B,
       }
     }
   }
-  return getBindingForFieldOrElementCommon(B, R, R->getElementType(),superR);
+  return getBindingForFieldOrElementCommon(B, R, R->getElementType());
 }
 
 SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
@@ -1557,7 +1556,7 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
     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(const SubRegion *LazyBindingRegion,
 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::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
   // 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::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
     
     // 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::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
       // 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();
       }
index e5efeb81f7d278e66c877b977ad2b7ae7e17d087..dd1cd4942f85f12f51819e7d1c25c5b82325800e 100644 (file)
@@ -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;
index 77de9dd3264608afc583bdf46c428d4099f923cf..bff22012c0c78516bb4077dbf3375c22ddb31913 100644 (file)
@@ -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.
index 5e9f1bcb836cf2d405435ca27be2ae749b794cd5..2369c09d22f1c4e490fa2b6bb58cdb3098a6c66f 100644 (file)
@@ -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 testGlobalInvalidationWithDirectBinding() {
   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}}
+}