diff options
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h | 10 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/MemRegion.cpp | 47 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/RegionStore.cpp | 61 |
3 files changed, 72 insertions, 46 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 2018bd2e44..1281cfbda9 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -52,11 +52,19 @@ class RegionOffset { int64_t Offset; public: + enum { Symbolic = INT64_MAX }; + RegionOffset() : R(0) {} RegionOffset(const MemRegion *r, int64_t off) : R(r), Offset(off) {} const MemRegion *getRegion() const { return R; } - int64_t getOffset() const { return Offset; } + + bool hasSymbolicOffset() const { return Offset == Symbolic; } + + int64_t getOffset() const { + assert(!hasSymbolicOffset()); + return Offset; + } bool isValid() const { return R; } }; diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index b2e7055c31..58abc9a280 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -1038,12 +1038,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(); + return RegionOffset(R, RegionOffset::Symbolic); + case SymbolicRegionKind: case AllocaRegionKind: case CompoundLiteralRegionKind: @@ -1053,6 +1055,7 @@ RegionOffset MemRegion::getAsOffset() const { case ObjCIvarRegionKind: case CXXTempObjectRegionKind: goto Finish; + case CXXBaseObjectRegionKind: { const CXXBaseObjectRegion *BOR = cast<CXXBaseObjectRegion>(R); R = BOR->getSuperRegion(); @@ -1070,8 +1073,14 @@ RegionOffset MemRegion::getAsOffset() const { const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl(); if (!Child) { // We cannot compute the offset of the base class. - return RegionOffset(); + 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; @@ -1087,29 +1096,46 @@ RegionOffset MemRegion::getAsOffset() const { } case ElementRegionKind: { const ElementRegion *ER = cast<ElementRegion>(R); - QualType EleTy = ER->getValueType(); + R = ER->getSuperRegion(); - if (!IsCompleteType(getContext(), EleTy)) - return RegionOffset(); + 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(); // This type size is in bits. Offset += i * getContext().getTypeSize(EleTy); } else { // We cannot compute offset for non-concrete index. - return RegionOffset(); + 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(); + 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(), @@ -1120,13 +1146,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); } diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index 90bd0f31a5..1ba46ea067 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -40,33 +40,42 @@ using llvm::Optional; namespace { class BindingKey { public: - enum Kind { Direct = 0x0, Default = 0x1 }; + enum Kind { Default = 0x0, Direct = 0x1 }; private: - enum { SYMBOLIC = UINT64_MAX }; + enum { Symbolic = 0x2 }; - llvm::PointerIntPair<const MemRegion *, 1, Kind> P; - uint64_t Offset; + llvm::PointerIntPair<const MemRegion *, 2> P; + uint64_t Data; - explicit BindingKey(const MemRegion *r, Kind k) - : P(r, k), Offset(SYMBOLIC) {} + explicit BindingKey(const MemRegion *r, const MemRegion *Base, Kind k) + : P(r, k | Symbolic), Data(reinterpret_cast<uintptr_t>(Base)) { + assert(r && Base && "Must have known regions."); + assert(getConcreteOffsetRegion() == Base && "Failed to store base region"); + } explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k) - : P(r, k), Offset(offset) {} + : P(r, k), Data(offset) { + assert(r && "Must have known regions."); + assert(getOffset() == offset && "Failed to store offset"); + } public: - bool isDirect() const { return P.getInt() == Direct; } - bool hasSymbolicOffset() const { return Offset == SYMBOLIC; } + bool isDirect() const { return P.getInt() & Direct; } + bool hasSymbolicOffset() const { return P.getInt() & Symbolic; } const MemRegion *getRegion() const { return P.getPointer(); } uint64_t getOffset() const { assert(!hasSymbolicOffset()); - return Offset; + return Data; } - const MemRegion *getConcreteOffsetRegion() const; + const MemRegion *getConcreteOffsetRegion() const { + assert(hasSymbolicOffset()); + return reinterpret_cast<const MemRegion *>(static_cast<uintptr_t>(Data)); + } void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddPointer(P.getOpaqueValue()); - ID.AddInteger(Offset); + ID.AddInteger(Data); } static BindingKey Make(const MemRegion *R, Kind k); @@ -76,12 +85,12 @@ public: return true; if (P.getOpaqueValue() > X.P.getOpaqueValue()) return false; - return Offset < X.Offset; + return Data < X.Data; } bool operator==(const BindingKey &X) const { return P.getOpaqueValue() == X.P.getOpaqueValue() && - Offset == X.Offset; + Data == X.Data; } bool isValid() const { @@ -92,27 +101,10 @@ public: BindingKey BindingKey::Make(const MemRegion *R, Kind k) { const RegionOffset &RO = R->getAsOffset(); - if (RO.isValid()) - return BindingKey(RO.getRegion(), RO.getOffset(), k); - - return BindingKey(R, k); -} - -const MemRegion *BindingKey::getConcreteOffsetRegion() const { - const MemRegion *R = getRegion(); - if (!hasSymbolicOffset()) - return R; - - RegionOffset RO; - do { - const SubRegion *SR = dyn_cast<SubRegion>(R); - if (!SR) - break; - R = SR->getSuperRegion(); - RO = R->getAsOffset(); - } while (!RO.isValid()); + if (RO.hasSymbolicOffset()) + return BindingKey(R, RO.getRegion(), k); - return R; + return BindingKey(RO.getRegion(), RO.getOffset(), k); } namespace llvm { @@ -561,7 +553,6 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B, // by changing the data structure used for RegionBindings. BindingKey SRKey = BindingKey::Make(R, BindingKey::Default); - assert(SRKey.isValid()); if (SRKey.hasSymbolicOffset()) { const SubRegion *Base = cast<SubRegion>(SRKey.getConcreteOffsetRegion()); B = removeSubRegionBindings(B, Base); |