summaryrefslogtreecommitdiffstats
path: root/lib/StaticAnalyzer/Core/MemRegion.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core/MemRegion.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp274
1 files changed, 231 insertions, 43 deletions
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index ed94c79..62e602a 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -179,7 +179,7 @@ const StackFrameContext *VarRegion::getStackFrame() const {
// Region extents.
//===----------------------------------------------------------------------===//
-DefinedOrUnknownSVal DeclRegion::getExtent(SValBuilder &svalBuilder) const {
+DefinedOrUnknownSVal TypedValueRegion::getExtent(SValBuilder &svalBuilder) const {
ASTContext &Ctx = svalBuilder.getContext();
QualType T = getDesugaredValueType(Ctx);
@@ -470,7 +470,7 @@ void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
}
void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {
- os << "base " << decl->getName();
+ os << "base{" << superRegion << ',' << decl->getName() << '}';
}
void CXXThisRegion::dumpToStream(raw_ostream &os) const {
@@ -518,10 +518,6 @@ void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
os << "StaticGlobalsMemSpace{" << CR << '}';
}
-void NonStaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
- os << "NonStaticGlobalSpaceRegion";
-}
-
void GlobalInternalSpaceRegion::dumpToStream(raw_ostream &os) const {
os << "GlobalInternalSpaceRegion";
}
@@ -534,17 +530,45 @@ void GlobalImmutableSpaceRegion::dumpToStream(raw_ostream &os) const {
os << "GlobalImmutableSpaceRegion";
}
-void MemRegion::dumpPretty(raw_ostream &os) const {
+void HeapSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "HeapSpaceRegion";
+}
+
+void UnknownSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "UnknownSpaceRegion";
+}
+
+void StackArgumentsSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "StackArgumentsSpaceRegion";
+}
+
+void StackLocalsSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "StackLocalsSpaceRegion";
+}
+
+bool MemRegion::canPrintPretty() const {
+ return false;
+}
+
+void MemRegion::printPretty(raw_ostream &os) const {
return;
}
-void VarRegion::dumpPretty(raw_ostream &os) const {
+bool VarRegion::canPrintPretty() const {
+ return true;
+}
+
+void VarRegion::printPretty(raw_ostream &os) const {
os << getDecl()->getName();
}
-void FieldRegion::dumpPretty(raw_ostream &os) const {
- superRegion->dumpPretty(os);
- os << "->" << getDecl();
+bool FieldRegion::canPrintPretty() const {
+ return superRegion->canPrintPretty();
+}
+
+void FieldRegion::printPretty(raw_ostream &os) const {
+ superRegion->printPretty(os);
+ os << "." << getDecl()->getName();
}
//===----------------------------------------------------------------------===//
@@ -643,6 +667,37 @@ MemRegionManager::getObjCStringRegion(const ObjCStringLiteral* Str){
return getSubRegion<ObjCStringRegion>(Str, getGlobalsRegion());
}
+/// Look through a chain of LocationContexts to either find the
+/// StackFrameContext that matches a DeclContext, or find a VarRegion
+/// for a variable captured by a block.
+static llvm::PointerUnion<const StackFrameContext *, const VarRegion *>
+getStackOrCaptureRegionForDeclContext(const LocationContext *LC,
+ const DeclContext *DC,
+ const VarDecl *VD) {
+ while (LC) {
+ if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC)) {
+ if (cast<DeclContext>(SFC->getDecl()) == DC)
+ return SFC;
+ }
+ if (const BlockInvocationContext *BC =
+ dyn_cast<BlockInvocationContext>(LC)) {
+ const BlockDataRegion *BR =
+ static_cast<const BlockDataRegion*>(BC->getContextData());
+ // FIXME: This can be made more efficient.
+ for (BlockDataRegion::referenced_vars_iterator
+ I = BR->referenced_vars_begin(),
+ E = BR->referenced_vars_end(); I != E; ++I) {
+ if (const VarRegion *VR = dyn_cast<VarRegion>(I.getOriginalRegion()))
+ if (VR->getDecl() == VD)
+ return cast<VarRegion>(I.getCapturedRegion());
+ }
+ }
+
+ LC = LC->getParent();
+ }
+ return (const StackFrameContext*)0;
+}
+
const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
const LocationContext *LC) {
const MemRegion *sReg = 0;
@@ -675,7 +730,13 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
// FIXME: Once we implement scope handling, we will need to properly lookup
// 'D' to the proper LocationContext.
const DeclContext *DC = D->getDeclContext();
- const StackFrameContext *STC = LC->getStackFrameForDeclContext(DC);
+ llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V =
+ getStackOrCaptureRegionForDeclContext(LC, DC, D);
+
+ if (V.is<const VarRegion*>())
+ return V.get<const VarRegion*>();
+
+ const StackFrameContext *STC = V.get<const StackFrameContext*>();
if (!STC)
sReg = getUnknownRegion();
@@ -800,6 +861,10 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) {
return getSubRegion<SymbolicRegion>(sym, getUnknownRegion());
}
+const SymbolicRegion *MemRegionManager::getSymbolicHeapRegion(SymbolRef Sym) {
+ return getSubRegion<SymbolicRegion>(Sym, getHeapRegion());
+}
+
const FieldRegion*
MemRegionManager::getFieldRegion(const FieldDecl *d,
const MemRegion* superRegion){
@@ -823,6 +888,37 @@ MemRegionManager::getCXXTempObjectRegion(Expr const *E,
const CXXBaseObjectRegion *
MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *decl,
const MemRegion *superRegion) {
+ // Check that the base class is actually a direct base of this region.
+ if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(superRegion)) {
+ if (const CXXRecordDecl *Class = TVR->getValueType()->getAsCXXRecordDecl()){
+ if (Class->isVirtuallyDerivedFrom(decl)) {
+ // Virtual base regions should not be layered, since the layout rules
+ // are different.
+ while (const CXXBaseObjectRegion *Base =
+ dyn_cast<CXXBaseObjectRegion>(superRegion)) {
+ superRegion = Base->getSuperRegion();
+ }
+ assert(superRegion && !isa<MemSpaceRegion>(superRegion));
+
+ } else {
+ // Non-virtual bases should always be direct bases.
+#ifndef NDEBUG
+ bool FoundBase = false;
+ for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
+ E = Class->bases_end();
+ I != E; ++I) {
+ if (I->getType()->getAsCXXRecordDecl() == decl) {
+ FoundBase = true;
+ break;
+ }
+ }
+
+ assert(FoundBase && "Not a direct base class of this region");
+#endif
+ }
+ }
+ }
+
return getSubRegion<CXXBaseObjectRegion>(decl, superRegion);
}
@@ -898,24 +994,26 @@ const MemRegion *MemRegion::getBaseRegion() const {
// View handling.
//===----------------------------------------------------------------------===//
-const MemRegion *MemRegion::StripCasts() const {
+const MemRegion *MemRegion::StripCasts(bool StripBaseCasts) const {
const MemRegion *R = this;
while (true) {
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- // FIXME: generalize. Essentially we want to strip away ElementRegions
- // that were layered on a symbolic region because of casts. We only
- // want to strip away ElementRegions, however, where the index is 0.
- SVal index = ER->getIndex();
- if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&index)) {
- if (CI->getValue().getSExtValue() == 0) {
- R = ER->getSuperRegion();
- continue;
- }
- }
+ switch (R->getKind()) {
+ case ElementRegionKind: {
+ const ElementRegion *ER = cast<ElementRegion>(R);
+ if (!ER->getIndex().isZeroConstant())
+ return R;
+ R = ER->getSuperRegion();
+ break;
+ }
+ case CXXBaseObjectRegionKind:
+ if (!StripBaseCasts)
+ return R;
+ R = cast<CXXBaseObjectRegion>(R)->getSuperRegion();
+ break;
+ default:
+ return R;
}
- break;
}
- return R;
}
// FIXME: Merge with the implementation of the same method in Store.cpp
@@ -973,12 +1071,14 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const {
RegionOffset MemRegion::getAsOffset() const {
const MemRegion *R = this;
+ const MemRegion *SymbolicOffsetBase = 0;
int64_t Offset = 0;
while (1) {
switch (R->getKind()) {
default:
- return RegionOffset(0);
+ return RegionOffset(R, RegionOffset::Symbolic);
+
case SymbolicRegionKind:
case AllocaRegionKind:
case CompoundLiteralRegionKind:
@@ -987,31 +1087,95 @@ RegionOffset MemRegion::getAsOffset() const {
case VarRegionKind:
case CXXTempObjectRegionKind:
goto Finish;
+
+ case ObjCIvarRegionKind:
+ // This is a little strange, but it's a compromise between
+ // ObjCIvarRegions having unknown compile-time offsets (when using the
+ // non-fragile runtime) and yet still being distinct, non-overlapping
+ // regions. Thus we treat them as "like" base regions for the purposes
+ // of computing offsets.
+ goto Finish;
+
+ case CXXBaseObjectRegionKind: {
+ const CXXBaseObjectRegion *BOR = cast<CXXBaseObjectRegion>(R);
+ R = BOR->getSuperRegion();
+
+ QualType Ty;
+ if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R)) {
+ Ty = TVR->getDesugaredValueType(getContext());
+ } else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
+ // If our base region is symbolic, we don't know what type it really is.
+ // Pretend the type of the symbol is the true dynamic type.
+ // (This will at least be self-consistent for the life of the symbol.)
+ Ty = SR->getSymbol()->getType(getContext())->getPointeeType();
+ }
+
+ const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl();
+ if (!Child) {
+ // We cannot compute the offset of the base class.
+ SymbolicOffsetBase = R;
+ }
+
+ // Don't bother calculating precise offsets if we already have a
+ // symbolic offset somewhere in the chain.
+ if (SymbolicOffsetBase)
+ continue;
+
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child);
+
+ CharUnits BaseOffset;
+ const CXXRecordDecl *Base = BOR->getDecl();
+ if (Child->isVirtuallyDerivedFrom(Base))
+ BaseOffset = Layout.getVBaseClassOffset(Base);
+ else
+ BaseOffset = Layout.getBaseClassOffset(Base);
+
+ // The base offset is in chars, not in bits.
+ Offset += BaseOffset.getQuantity() * getContext().getCharWidth();
+ break;
+ }
case ElementRegionKind: {
const ElementRegion *ER = cast<ElementRegion>(R);
- QualType EleTy = ER->getValueType();
+ R = ER->getSuperRegion();
- if (!IsCompleteType(getContext(), EleTy))
- return RegionOffset(0);
+ QualType EleTy = ER->getValueType();
+ if (!IsCompleteType(getContext(), EleTy)) {
+ // We cannot compute the offset of the base class.
+ SymbolicOffsetBase = R;
+ continue;
+ }
SVal Index = ER->getIndex();
if (const nonloc::ConcreteInt *CI=dyn_cast<nonloc::ConcreteInt>(&Index)) {
+ // Don't bother calculating precise offsets if we already have a
+ // symbolic offset somewhere in the chain.
+ if (SymbolicOffsetBase)
+ continue;
+
int64_t i = CI->getValue().getSExtValue();
- CharUnits Size = getContext().getTypeSizeInChars(EleTy);
- Offset += i * Size.getQuantity() * 8;
+ // This type size is in bits.
+ Offset += i * getContext().getTypeSize(EleTy);
} else {
// We cannot compute offset for non-concrete index.
- return RegionOffset(0);
+ SymbolicOffsetBase = R;
}
- R = ER->getSuperRegion();
break;
}
case FieldRegionKind: {
const FieldRegion *FR = cast<FieldRegion>(R);
+ R = FR->getSuperRegion();
+
const RecordDecl *RD = FR->getDecl()->getParent();
- if (!RD->isCompleteDefinition())
+ if (!RD->isCompleteDefinition()) {
// We cannot compute offset for incomplete type.
- return RegionOffset(0);
+ SymbolicOffsetBase = R;
+ }
+
+ // Don't bother calculating precise offsets if we already have a
+ // symbolic offset somewhere in the chain.
+ if (SymbolicOffsetBase)
+ continue;
+
// Get the field number.
unsigned idx = 0;
for (RecordDecl::field_iterator FI = RD->field_begin(),
@@ -1022,13 +1186,14 @@ RegionOffset MemRegion::getAsOffset() const {
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
// This is offset in bits.
Offset += Layout.getFieldOffset(idx);
- R = FR->getSuperRegion();
break;
}
}
}
Finish:
+ if (SymbolicOffsetBase)
+ return RegionOffset(SymbolicOffsetBase, RegionOffset::Symbolic);
return RegionOffset(R, Offset);
}
@@ -1056,26 +1221,37 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
typedef BumpVector<const MemRegion*> VarVec;
VarVec *BV = (VarVec*) A.Allocate<VarVec>();
new (BV) VarVec(BC, E - I);
+ VarVec *BVOriginal = (VarVec*) A.Allocate<VarVec>();
+ new (BVOriginal) VarVec(BC, E - I);
for ( ; I != E; ++I) {
const VarDecl *VD = *I;
const VarRegion *VR = 0;
+ const VarRegion *OriginalVR = 0;
- if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage())
+ if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage()) {
VR = MemMgr.getVarRegion(VD, this);
+ OriginalVR = MemMgr.getVarRegion(VD, LC);
+ }
else {
- if (LC)
+ if (LC) {
VR = MemMgr.getVarRegion(VD, LC);
+ OriginalVR = VR;
+ }
else {
VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion());
+ OriginalVR = MemMgr.getVarRegion(VD, LC);
}
}
assert(VR);
+ assert(OriginalVR);
BV->push_back(VR, BC);
+ BVOriginal->push_back(OriginalVR, BC);
}
ReferencedVars = BV;
+ OriginalVars = BVOriginal;
}
BlockDataRegion::referenced_vars_iterator
@@ -1085,8 +1261,14 @@ BlockDataRegion::referenced_vars_begin() const {
BumpVector<const MemRegion*> *Vec =
static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
- return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ?
- NULL : Vec->begin());
+ if (Vec == (void*) 0x1)
+ return BlockDataRegion::referenced_vars_iterator(0, 0);
+
+ BumpVector<const MemRegion*> *VecOriginal =
+ static_cast<BumpVector<const MemRegion*>*>(OriginalVars);
+
+ return BlockDataRegion::referenced_vars_iterator(Vec->begin(),
+ VecOriginal->begin());
}
BlockDataRegion::referenced_vars_iterator
@@ -1096,6 +1278,12 @@ BlockDataRegion::referenced_vars_end() const {
BumpVector<const MemRegion*> *Vec =
static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
- return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ?
- NULL : Vec->end());
+ if (Vec == (void*) 0x1)
+ return BlockDataRegion::referenced_vars_iterator(0, 0);
+
+ BumpVector<const MemRegion*> *VecOriginal =
+ static_cast<BumpVector<const MemRegion*>*>(OriginalVars);
+
+ return BlockDataRegion::referenced_vars_iterator(Vec->end(),
+ VecOriginal->end());
}
OpenPOWER on IntegriCloud