mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-14 11:39:35 +00:00
[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:
parent
577749a337
commit
fa80736bca
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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}}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user