diff --git a/clang/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h index 6ba3dc68fcf7..6e5790456c15 100644 --- a/clang/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h +++ b/clang/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h @@ -872,6 +872,8 @@ class CXXBaseObjectRegion : public TypedRegion { const CXXRecordDecl *decl, const MemRegion *sReg); public: + const CXXRecordDecl *getDecl() const { return decl; } + QualType getValueType() const; void dumpToStream(llvm::raw_ostream& os) const; @@ -1012,6 +1014,14 @@ public: const CXXBaseObjectRegion *getCXXBaseObjectRegion(const CXXRecordDecl *decl, 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 BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, CanQualType locTy, diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index 1577cbee3155..874e7a306421 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -643,36 +643,52 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, // We don't set EntryNode and currentStmt. And we don't clean up state. const CXXCtorInitializer *BMI = Init.getInitializer(); - ExplodedNode *Pred = builder.getPredecessor(); - const LocationContext *LC = Pred->getLocationContext(); + ExplodedNode *pred = builder.getPredecessor(); + + const StackFrameContext *stackFrame = cast(pred->getLocationContext()); + const CXXConstructorDecl *decl = cast(stackFrame->getDecl()); + const CXXThisRegion *thisReg = getCXXThisRegion(decl, stackFrame); + + SVal thisVal = pred->getState()->getSVal(thisReg); if (BMI->isAnyMemberInitializer()) { ExplodedNodeSet Dst; // 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){ ExplodedNode *Pred = *I; const GRState *state = Pred->getState(); const FieldDecl *FD = BMI->getAnyMember(); - const RecordDecl *RD = FD->getParent(); - const CXXThisRegion *ThisR = getCXXThisRegion(cast(RD), - cast(LC)); - SVal ThisV = state->getSVal(ThisR); - SVal FieldLoc = state->getLValue(FD, ThisV); + SVal FieldLoc = state->getLValue(FD, thisVal); SVal InitVal = state->getSVal(BMI->getInit()); state = state->bindLoc(FieldLoc, InitVal); // Use a custom node building process. - PostInitializer PP(BMI, LC); + PostInitializer PP(BMI, stackFrame); // Builder automatically add the generated node to the deferred set, // which are processed in the builder's dtor. builder.generateNode(PP, state, Pred); } + return; } + + assert(BMI->isBaseInitializer()); + + // Get the base class declaration. + const CXXConstructExpr *ctorExpr = cast(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, diff --git a/clang/lib/StaticAnalyzer/RegionStore.cpp b/clang/lib/StaticAnalyzer/RegionStore.cpp index e47a77e6fc8f..58cec3031329 100644 --- a/clang/lib/StaticAnalyzer/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/RegionStore.cpp @@ -822,7 +822,8 @@ SVal RegionStoreManager::evalDerivedToBase(SVal derived, QualType baseType) { return derived; const MemRegion *baseReg = - MRMgr.getCXXBaseObjectRegion(baseDecl, derivedRegVal->getRegion()); + MRMgr.getCXXBaseObjectRegion(baseDecl, derivedRegVal->getRegion()); + return loc::MemRegionVal(baseReg); } //===----------------------------------------------------------------------===// @@ -1105,6 +1106,17 @@ RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) { return std::make_pair(X.first, 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(R)) { + const std::pair &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 // possible for a valid lazy binding. 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, SVal DefaultVal) { - BindingKey key = BindingKey::Make(R, BindingKey::Default); // The BindingKey may be "invalid" if we cannot handle the region binding @@ -1582,7 +1593,7 @@ Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R, // the case of nested symbolic indices, we need to march up the region // hierarchy untile we reach a region whose binding we can reason about. const SubRegion *subReg = R; - + while (!key.isValid()) { if (const SubRegion *tmp = dyn_cast(subReg->getSuperRegion())) { subReg = tmp; diff --git a/clang/test/Analysis/base-init.cpp b/clang/test/Analysis/base-init.cpp new file mode 100644 index 000000000000..e82f443ced94 --- /dev/null +++ b/clang/test/Analysis/base-init.cpp @@ -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 + } +}