forked from OSchip/llvm-project
[analyzer] Create a temporary region for rvalue structs when accessing fields
Struct rvalues are represented in the analyzer by CompoundVals, LazyCompoundVals, or plain ConjuredSymbols -- none of which have associated regions. If the entire structure is going to persist, this is not a problem -- either the rvalue will be assigned to an existing region, or a MaterializeTemporaryExpr will be present to create a temporary region. However, if we just need a field from the struct, we need to create the temporary region ourselves. This is inspired by the way CodeGen handles calls to temporaries; support for that in the analyzer is coming next. Part of <rdar://problem/12137950> llvm-svn: 164828
This commit is contained in:
parent
5721daae02
commit
e7126582a4
|
@ -1505,17 +1505,17 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
|
||||||
ProgramStateRef state = Pred->getState();
|
ProgramStateRef state = Pred->getState();
|
||||||
const LocationContext *LCtx = Pred->getLocationContext();
|
const LocationContext *LCtx = Pred->getLocationContext();
|
||||||
SVal baseExprVal = state->getSVal(baseExpr, Pred->getLocationContext());
|
SVal baseExprVal = state->getSVal(baseExpr, Pred->getLocationContext());
|
||||||
if (isa<nonloc::LazyCompoundVal>(baseExprVal) ||
|
|
||||||
isa<nonloc::CompoundVal>(baseExprVal) ||
|
// If we're accessing a field of an rvalue, we need to treat it like a
|
||||||
// FIXME: This can originate by conjuring a symbol for an unknown
|
// temporary object.
|
||||||
// temporary struct object, see test/Analysis/fields.c:
|
if (isa<NonLoc>(baseExprVal)) {
|
||||||
// (p = getit()).x
|
const MemRegion *R =
|
||||||
isa<nonloc::SymbolVal>(baseExprVal)) {
|
svalBuilder.getRegionManager().getCXXTempObjectRegion(baseExpr, LCtx);
|
||||||
Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, UnknownVal()));
|
SVal L = loc::MemRegionVal(R);
|
||||||
return;
|
state = state->bindLoc(L, baseExprVal);
|
||||||
|
baseExprVal = L;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For all other cases, compute an lvalue.
|
|
||||||
SVal L = state->getLValue(field, baseExprVal);
|
SVal L = state->getLValue(field, baseExprVal);
|
||||||
if (M->isGLValue()) {
|
if (M->isGLValue()) {
|
||||||
ExplodedNodeSet Tmp;
|
ExplodedNodeSet Tmp;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core %s -analyzer-store=region -verify
|
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection %s -analyzer-store=region -verify
|
||||||
|
|
||||||
|
void clang_analyzer_eval(int);
|
||||||
|
|
||||||
unsigned foo();
|
unsigned foo();
|
||||||
typedef struct bf { unsigned x:2; } bf;
|
typedef struct bf { unsigned x:2; } bf;
|
||||||
|
@ -33,3 +35,10 @@ void testNullAddress() {
|
||||||
int *px = &p->x; // expected-warning{{Access to field 'x' results in a dereference of a null pointer (loaded from variable 'p')}}
|
int *px = &p->x; // expected-warning{{Access to field 'x' results in a dereference of a null pointer (loaded from variable 'p')}}
|
||||||
*px = 1; // No warning because analysis stops at the previous line.
|
*px = 1; // No warning because analysis stops at the previous line.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testLazyCompoundVal() {
|
||||||
|
Point p = {42, 0};
|
||||||
|
Point q;
|
||||||
|
clang_analyzer_eval((q = p).x == 42); // expected-warning{{TRUE}}
|
||||||
|
clang_analyzer_eval(q.x == 42); // expected-warning{{TRUE}}
|
||||||
|
}
|
||||||
|
|
|
@ -116,10 +116,8 @@ void testReferenceAddress(int &x) {
|
||||||
|
|
||||||
struct S { int &x; };
|
struct S { int &x; };
|
||||||
|
|
||||||
// FIXME: Should be TRUE. Fields of return-by-value structs are not yet
|
|
||||||
// symbolicated. Tracked by <rdar://problem/12137950>.
|
|
||||||
extern S getS();
|
extern S getS();
|
||||||
clang_analyzer_eval(&getS().x != 0); // expected-warning{{UNKNOWN}}
|
clang_analyzer_eval(&getS().x != 0); // expected-warning{{TRUE}}
|
||||||
|
|
||||||
extern S *getSP();
|
extern S *getSP();
|
||||||
clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{TRUE}}
|
clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{TRUE}}
|
||||||
|
|
Loading…
Reference in New Issue