diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/MemRegion.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/MemRegion.cpp | 274 |
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()); } |