[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>

llvm-svn: 179554
This commit is contained in:
Jordan Rose 2013-04-15 20:39:45 +00:00
parent 577749a337
commit fa80736bca
4 changed files with 152 additions and 13 deletions

View 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();
}

View 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;

View 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.

View 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}}
}