forked from OSchip/llvm-project
Support inlining base initializers. We still haven't got it completely right,
since the bindings are purged after they are set up. Need to investigate RemoveDeadBindings algorithm. llvm-svn: 123374
This commit is contained in:
parent
ad000d8f16
commit
0d87e0c65b
|
@ -872,6 +872,8 @@ class CXXBaseObjectRegion : public TypedRegion {
|
||||||
const CXXRecordDecl *decl, const MemRegion *sReg);
|
const CXXRecordDecl *decl, const MemRegion *sReg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
const CXXRecordDecl *getDecl() const { return decl; }
|
||||||
|
|
||||||
QualType getValueType() const;
|
QualType getValueType() const;
|
||||||
|
|
||||||
void dumpToStream(llvm::raw_ostream& os) const;
|
void dumpToStream(llvm::raw_ostream& os) const;
|
||||||
|
@ -1012,6 +1014,14 @@ public:
|
||||||
const CXXBaseObjectRegion *getCXXBaseObjectRegion(const CXXRecordDecl *decl,
|
const CXXBaseObjectRegion *getCXXBaseObjectRegion(const CXXRecordDecl *decl,
|
||||||
const MemRegion *superRegion);
|
const MemRegion *superRegion);
|
||||||
|
|
||||||
|
/// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different
|
||||||
|
/// super region.
|
||||||
|
const CXXBaseObjectRegion *
|
||||||
|
getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg,
|
||||||
|
const MemRegion *superRegion) {
|
||||||
|
return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion);
|
||||||
|
}
|
||||||
|
|
||||||
const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD);
|
const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD);
|
||||||
const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD,
|
const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD,
|
||||||
CanQualType locTy,
|
CanQualType locTy,
|
||||||
|
|
|
@ -643,36 +643,52 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
|
||||||
// We don't set EntryNode and currentStmt. And we don't clean up state.
|
// We don't set EntryNode and currentStmt. And we don't clean up state.
|
||||||
const CXXCtorInitializer *BMI = Init.getInitializer();
|
const CXXCtorInitializer *BMI = Init.getInitializer();
|
||||||
|
|
||||||
ExplodedNode *Pred = builder.getPredecessor();
|
ExplodedNode *pred = builder.getPredecessor();
|
||||||
const LocationContext *LC = Pred->getLocationContext();
|
|
||||||
|
const StackFrameContext *stackFrame = cast<StackFrameContext>(pred->getLocationContext());
|
||||||
|
const CXXConstructorDecl *decl = cast<CXXConstructorDecl>(stackFrame->getDecl());
|
||||||
|
const CXXThisRegion *thisReg = getCXXThisRegion(decl, stackFrame);
|
||||||
|
|
||||||
|
SVal thisVal = pred->getState()->getSVal(thisReg);
|
||||||
|
|
||||||
if (BMI->isAnyMemberInitializer()) {
|
if (BMI->isAnyMemberInitializer()) {
|
||||||
ExplodedNodeSet Dst;
|
ExplodedNodeSet Dst;
|
||||||
|
|
||||||
// Evaluate the initializer.
|
// Evaluate the initializer.
|
||||||
Visit(BMI->getInit(), Pred, Dst);
|
Visit(BMI->getInit(), pred, Dst);
|
||||||
|
|
||||||
for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I){
|
for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I){
|
||||||
ExplodedNode *Pred = *I;
|
ExplodedNode *Pred = *I;
|
||||||
const GRState *state = Pred->getState();
|
const GRState *state = Pred->getState();
|
||||||
|
|
||||||
const FieldDecl *FD = BMI->getAnyMember();
|
const FieldDecl *FD = BMI->getAnyMember();
|
||||||
const RecordDecl *RD = FD->getParent();
|
|
||||||
const CXXThisRegion *ThisR = getCXXThisRegion(cast<CXXRecordDecl>(RD),
|
|
||||||
cast<StackFrameContext>(LC));
|
|
||||||
|
|
||||||
SVal ThisV = state->getSVal(ThisR);
|
SVal FieldLoc = state->getLValue(FD, thisVal);
|
||||||
SVal FieldLoc = state->getLValue(FD, ThisV);
|
|
||||||
SVal InitVal = state->getSVal(BMI->getInit());
|
SVal InitVal = state->getSVal(BMI->getInit());
|
||||||
state = state->bindLoc(FieldLoc, InitVal);
|
state = state->bindLoc(FieldLoc, InitVal);
|
||||||
|
|
||||||
// Use a custom node building process.
|
// Use a custom node building process.
|
||||||
PostInitializer PP(BMI, LC);
|
PostInitializer PP(BMI, stackFrame);
|
||||||
// Builder automatically add the generated node to the deferred set,
|
// Builder automatically add the generated node to the deferred set,
|
||||||
// which are processed in the builder's dtor.
|
// which are processed in the builder's dtor.
|
||||||
builder.generateNode(PP, state, Pred);
|
builder.generateNode(PP, state, Pred);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(BMI->isBaseInitializer());
|
||||||
|
|
||||||
|
// Get the base class declaration.
|
||||||
|
const CXXConstructExpr *ctorExpr = cast<CXXConstructExpr>(BMI->getInit());
|
||||||
|
|
||||||
|
// Create the base object region.
|
||||||
|
SVal baseVal =
|
||||||
|
getStoreManager().evalDerivedToBase(thisVal, ctorExpr->getType());
|
||||||
|
const MemRegion *baseReg = baseVal.getAsRegion();
|
||||||
|
assert(baseReg);
|
||||||
|
Builder = &builder;
|
||||||
|
ExplodedNodeSet dst;
|
||||||
|
VisitCXXConstructExpr(ctorExpr, baseReg, pred, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
|
void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
|
||||||
|
|
|
@ -823,6 +823,7 @@ SVal RegionStoreManager::evalDerivedToBase(SVal derived, QualType baseType) {
|
||||||
|
|
||||||
const MemRegion *baseReg =
|
const MemRegion *baseReg =
|
||||||
MRMgr.getCXXBaseObjectRegion(baseDecl, derivedRegVal->getRegion());
|
MRMgr.getCXXBaseObjectRegion(baseDecl, derivedRegVal->getRegion());
|
||||||
|
|
||||||
return loc::MemRegionVal(baseReg);
|
return loc::MemRegionVal(baseReg);
|
||||||
}
|
}
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -1105,6 +1106,17 @@ RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) {
|
||||||
return std::make_pair(X.first,
|
return std::make_pair(X.first,
|
||||||
MRMgr.getFieldRegionWithSuper(FR, X.second));
|
MRMgr.getFieldRegionWithSuper(FR, X.second));
|
||||||
}
|
}
|
||||||
|
// C++ base object region is another kind of region that we should blast
|
||||||
|
// through to look for lazy compound value. It is like a field region.
|
||||||
|
else if (const CXXBaseObjectRegion *baseReg =
|
||||||
|
dyn_cast<CXXBaseObjectRegion>(R)) {
|
||||||
|
const std::pair<Store, const MemRegion *> &X =
|
||||||
|
GetLazyBinding(B, baseReg->getSuperRegion());
|
||||||
|
|
||||||
|
if (X.second)
|
||||||
|
return std::make_pair(X.first,
|
||||||
|
MRMgr.getCXXBaseObjectRegionWithSuper(baseReg, X.second));
|
||||||
|
}
|
||||||
// The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is
|
// The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is
|
||||||
// possible for a valid lazy binding.
|
// possible for a valid lazy binding.
|
||||||
return std::make_pair((Store) 0, (const MemRegion *) 0);
|
return std::make_pair((Store) 0, (const MemRegion *) 0);
|
||||||
|
@ -1572,7 +1584,6 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
|
||||||
|
|
||||||
Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R,
|
Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R,
|
||||||
SVal DefaultVal) {
|
SVal DefaultVal) {
|
||||||
|
|
||||||
BindingKey key = BindingKey::Make(R, BindingKey::Default);
|
BindingKey key = BindingKey::Make(R, BindingKey::Default);
|
||||||
|
|
||||||
// The BindingKey may be "invalid" if we cannot handle the region binding
|
// The BindingKey may be "invalid" if we cannot handle the region binding
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -analyzer-inline-call -cfg-add-initializers -verify -analyzer-no-purge-dead %s
|
||||||
|
|
||||||
|
class A {
|
||||||
|
int x;
|
||||||
|
public:
|
||||||
|
A();
|
||||||
|
int getx() const {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
A::A() : x(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : public A {
|
||||||
|
int y;
|
||||||
|
public:
|
||||||
|
B();
|
||||||
|
};
|
||||||
|
|
||||||
|
B::B() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void f() {
|
||||||
|
B b;
|
||||||
|
if (b.getx() != 0) {
|
||||||
|
int *p = 0;
|
||||||
|
*p = 0; // no-warning
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue