diff options
-rw-r--r-- | lib/StaticAnalyzer/Core/RegionStore.cpp | 19 | ||||
-rw-r--r-- | test/Analysis/Inputs/system-header-simulator.h | 4 | ||||
-rw-r--r-- | test/Analysis/global-region-invalidation.c | 5 | ||||
-rw-r--r-- | test/Analysis/global_region_invalidation.mm | 137 |
4 files changed, 152 insertions, 13 deletions
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<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(); } 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}} +} |