From: Jordan Rose Date: Mon, 15 Apr 2013 20:39:45 +0000 (+0000) Subject: [analyzer] Re-enable using global regions as a symbolic base. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=262e0d41e49c6b823d62743535e2accb117a6ea9;p=clang [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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179554 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index 09ee549ebb..eeaf51d8ee 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -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 @@ -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(superR); - while (Base) { + const SubRegion *SR = dyn_cast(R); + while (SR) { + const MemRegion *Base = SR->getSuperRegion(); if (Optional D = getBindingForDerivedDefaultValue(B, Base, R, Ty)) { if (D->getAs()) { 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(Base->getSuperRegion()); + SR = dyn_cast(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(superR)) { + dyn_cast(R->getSuperRegion())) { if (typedSuperR->getValueType()->isVectorType()) return UnknownVal(); } diff --git a/test/Analysis/Inputs/system-header-simulator.h b/test/Analysis/Inputs/system-header-simulator.h index e5efeb81f7..dd1cd4942f 100644 --- a/test/Analysis/Inputs/system-header-simulator.h +++ b/test/Analysis/Inputs/system-header-simulator.h @@ -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; diff --git a/test/Analysis/global-region-invalidation.c b/test/Analysis/global-region-invalidation.c index 77de9dd326..bff22012c0 100644 --- a/test/Analysis/global-region-invalidation.c +++ b/test/Analysis/global-region-invalidation.c @@ -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. diff --git a/test/Analysis/global_region_invalidation.mm b/test/Analysis/global_region_invalidation.mm index 5e9f1bcb83..2369c09d22 100644 --- a/test/Analysis/global_region_invalidation.mm +++ b/test/Analysis/global_region_invalidation.mm @@ -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}} +}