| //==- MemRegion.h - Abstract memory regions for static analysis -*- C++ -*--==// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines MemRegion and its subclasses. MemRegion defines a |
| // partially-typed abstraction of memory useful for path-sensitive dataflow |
| // analyses. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H |
| #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H |
| |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/CharUnits.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/AST/DeclarationName.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/AST/ExprObjC.h" |
| #include "clang/AST/Type.h" |
| #include "clang/Analysis/AnalysisDeclContext.h" |
| #include "clang/Basic/LLVM.h" |
| #include "clang/Basic/SourceLocation.h" |
| #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" |
| #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/FoldingSet.h" |
| #include "llvm/ADT/Optional.h" |
| #include "llvm/ADT/PointerIntPair.h" |
| #include "llvm/Support/Allocator.h" |
| #include "llvm/Support/Casting.h" |
| #include <cassert> |
| #include <cstdint> |
| #include <limits> |
| #include <string> |
| #include <utility> |
| |
| namespace clang { |
| |
| class AnalysisDeclContext; |
| class CXXRecordDecl; |
| class Decl; |
| class LocationContext; |
| class StackFrameContext; |
| |
| namespace ento { |
| |
| class CodeTextRegion; |
| class MemRegion; |
| class MemRegionManager; |
| class MemSpaceRegion; |
| class SValBuilder; |
| class SymbolicRegion; |
| class VarRegion; |
| |
| /// Represent a region's offset within the top level base region. |
| class RegionOffset { |
| /// The base region. |
| const MemRegion *R = nullptr; |
| |
| /// The bit offset within the base region. Can be negative. |
| int64_t Offset; |
| |
| public: |
| // We're using a const instead of an enumeration due to the size required; |
| // Visual Studio will only create enumerations of size int, not long long. |
| static const int64_t Symbolic = std::numeric_limits<int64_t>::max(); |
| |
| RegionOffset() = default; |
| RegionOffset(const MemRegion *r, int64_t off) : R(r), Offset(off) {} |
| |
| const MemRegion *getRegion() const { return R; } |
| |
| bool hasSymbolicOffset() const { return Offset == Symbolic; } |
| |
| int64_t getOffset() const { |
| assert(!hasSymbolicOffset()); |
| return Offset; |
| } |
| |
| bool isValid() const { return R; } |
| }; |
| |
| //===----------------------------------------------------------------------===// |
| // Base region classes. |
| //===----------------------------------------------------------------------===// |
| |
| /// MemRegion - The root abstract class for all memory regions. |
| class MemRegion : public llvm::FoldingSetNode { |
| public: |
| enum Kind { |
| #define REGION(Id, Parent) Id ## Kind, |
| #define REGION_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last, |
| #include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def" |
| }; |
| |
| private: |
| const Kind kind; |
| mutable Optional<RegionOffset> cachedOffset; |
| |
| protected: |
| MemRegion(Kind k) : kind(k) {} |
| virtual ~MemRegion(); |
| |
| public: |
| ASTContext &getContext() const; |
| |
| virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0; |
| |
| virtual MemRegionManager* getMemRegionManager() const = 0; |
| |
| const MemSpaceRegion *getMemorySpace() const; |
| |
| const MemRegion *getBaseRegion() const; |
| |
| /// Recursively retrieve the region of the most derived class instance of |
| /// regions of C++ base class instances. |
| const MemRegion *getMostDerivedObjectRegion() const; |
| |
| /// Check if the region is a subregion of the given region. |
| /// Each region is a subregion of itself. |
| virtual bool isSubRegionOf(const MemRegion *R) const; |
| |
| const MemRegion *StripCasts(bool StripBaseAndDerivedCasts = true) const; |
| |
| /// If this is a symbolic region, returns the region. Otherwise, |
| /// goes up the base chain looking for the first symbolic base region. |
| const SymbolicRegion *getSymbolicBase() const; |
| |
| bool hasGlobalsOrParametersStorage() const; |
| |
| bool hasStackStorage() const; |
| |
| bool hasStackNonParametersStorage() const; |
| |
| bool hasStackParametersStorage() const; |
| |
| /// Compute the offset within the top level memory object. |
| RegionOffset getAsOffset() const; |
| |
| /// Get a string representation of a region for debug use. |
| std::string getString() const; |
| |
| virtual void dumpToStream(raw_ostream &os) const; |
| |
| void dump() const; |
| |
| /// Returns true if this region can be printed in a user-friendly way. |
| virtual bool canPrintPretty() const; |
| |
| /// Print the region for use in diagnostics. |
| virtual void printPretty(raw_ostream &os) const; |
| |
| /// Returns true if this region's textual representation can be used |
| /// as part of a larger expression. |
| virtual bool canPrintPrettyAsExpr() const; |
| |
| /// Print the region as expression. |
| /// |
| /// When this region represents a subexpression, the method is for printing |
| /// an expression containing it. |
| virtual void printPrettyAsExpr(raw_ostream &os) const; |
| |
| Kind getKind() const { return kind; } |
| |
| template<typename RegionTy> const RegionTy* getAs() const; |
| |
| virtual bool isBoundable() const { return false; } |
| |
| /// Get descriptive name for memory region. The name is obtained from |
| /// the variable/field declaration retrieved from the memory region. |
| /// Regions that point to an element of an array are returned as: "arr[0]". |
| /// Regions that point to a struct are returned as: "st.var". |
| // |
| /// \param UseQuotes Set if the name should be quoted. |
| /// |
| /// \returns variable name for memory region |
| std::string getDescriptiveName(bool UseQuotes = true) const; |
| |
| /// Retrieve source range from memory region. The range retrieval |
| /// is based on the decl obtained from the memory region. |
| /// For a VarRegion the range of the base region is returned. |
| /// For a FieldRegion the range of the field is returned. |
| /// If no declaration is found, an empty source range is returned. |
| /// The client is responsible for checking if the returned range is valid. |
| /// |
| /// \returns source range for declaration retrieved from memory region |
| SourceRange sourceRange() const; |
| }; |
| |
| /// MemSpaceRegion - A memory region that represents a "memory space"; |
| /// for example, the set of global variables, the stack frame, etc. |
| class MemSpaceRegion : public MemRegion { |
| protected: |
| MemRegionManager *Mgr; |
| |
| MemSpaceRegion(MemRegionManager *mgr, Kind k) : MemRegion(k), Mgr(mgr) { |
| assert(classof(this)); |
| assert(mgr); |
| } |
| |
| MemRegionManager* getMemRegionManager() const override { return Mgr; } |
| |
| public: |
| bool isBoundable() const override { return false; } |
| |
| void Profile(llvm::FoldingSetNodeID &ID) const override; |
| |
| static bool classof(const MemRegion *R) { |
| Kind k = R->getKind(); |
| return k >= BEGIN_MEMSPACES && k <= END_MEMSPACES; |
| } |
| }; |
| |
| /// CodeSpaceRegion - The memory space that holds the executable code of |
| /// functions and blocks. |
| class CodeSpaceRegion : public MemSpaceRegion { |
| friend class MemRegionManager; |
| |
| CodeSpaceRegion(MemRegionManager *mgr) |
| : MemSpaceRegion(mgr, CodeSpaceRegionKind) {} |
| |
| public: |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion *R) { |
| return R->getKind() == CodeSpaceRegionKind; |
| } |
| }; |
| |
| class GlobalsSpaceRegion : public MemSpaceRegion { |
| virtual void anchor(); |
| |
| protected: |
| GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) : MemSpaceRegion(mgr, k) { |
| assert(classof(this)); |
| } |
| |
| public: |
| static bool classof(const MemRegion *R) { |
| Kind k = R->getKind(); |
| return k >= BEGIN_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES; |
| } |
| }; |
| |
| /// The region of the static variables within the current CodeTextRegion |
| /// scope. |
| /// |
| /// Currently, only the static locals are placed there, so we know that these |
| /// variables do not get invalidated by calls to other functions. |
| class StaticGlobalSpaceRegion : public GlobalsSpaceRegion { |
| friend class MemRegionManager; |
| |
| const CodeTextRegion *CR; |
| |
| StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr) |
| : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) { |
| assert(cr); |
| } |
| |
| public: |
| void Profile(llvm::FoldingSetNodeID &ID) const override; |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| const CodeTextRegion *getCodeRegion() const { return CR; } |
| |
| static bool classof(const MemRegion *R) { |
| return R->getKind() == StaticGlobalSpaceRegionKind; |
| } |
| }; |
| |
| /// The region for all the non-static global variables. |
| /// |
| /// This class is further split into subclasses for efficient implementation of |
| /// invalidating a set of related global values as is done in |
| /// RegionStoreManager::invalidateRegions (instead of finding all the dependent |
| /// globals, we invalidate the whole parent region). |
| class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion { |
| void anchor() override; |
| |
| protected: |
| NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k) |
| : GlobalsSpaceRegion(mgr, k) { |
| assert(classof(this)); |
| } |
| |
| public: |
| static bool classof(const MemRegion *R) { |
| Kind k = R->getKind(); |
| return k >= BEGIN_NON_STATIC_GLOBAL_MEMSPACES && |
| k <= END_NON_STATIC_GLOBAL_MEMSPACES; |
| } |
| }; |
| |
| /// The region containing globals which are defined in system/external |
| /// headers and are considered modifiable by system calls (ex: errno). |
| class GlobalSystemSpaceRegion : public NonStaticGlobalSpaceRegion { |
| friend class MemRegionManager; |
| |
| GlobalSystemSpaceRegion(MemRegionManager *mgr) |
| : NonStaticGlobalSpaceRegion(mgr, GlobalSystemSpaceRegionKind) {} |
| |
| public: |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion *R) { |
| return R->getKind() == GlobalSystemSpaceRegionKind; |
| } |
| }; |
| |
| /// The region containing globals which are considered not to be modified |
| /// or point to data which could be modified as a result of a function call |
| /// (system or internal). Ex: Const global scalars would be modeled as part of |
| /// this region. This region also includes most system globals since they have |
| /// low chance of being modified. |
| class GlobalImmutableSpaceRegion : public NonStaticGlobalSpaceRegion { |
| friend class MemRegionManager; |
| |
| GlobalImmutableSpaceRegion(MemRegionManager *mgr) |
| : NonStaticGlobalSpaceRegion(mgr, GlobalImmutableSpaceRegionKind) {} |
| |
| public: |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion *R) { |
| return R->getKind() == GlobalImmutableSpaceRegionKind; |
| } |
| }; |
| |
| /// The region containing globals which can be modified by calls to |
| /// "internally" defined functions - (for now just) functions other then system |
| /// calls. |
| class GlobalInternalSpaceRegion : public NonStaticGlobalSpaceRegion { |
| friend class MemRegionManager; |
| |
| GlobalInternalSpaceRegion(MemRegionManager *mgr) |
| : NonStaticGlobalSpaceRegion(mgr, GlobalInternalSpaceRegionKind) {} |
| |
| public: |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion *R) { |
| return R->getKind() == GlobalInternalSpaceRegionKind; |
| } |
| }; |
| |
| class HeapSpaceRegion : public MemSpaceRegion { |
| friend class MemRegionManager; |
| |
| HeapSpaceRegion(MemRegionManager *mgr) |
| : MemSpaceRegion(mgr, HeapSpaceRegionKind) {} |
| |
| public: |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion *R) { |
| return R->getKind() == HeapSpaceRegionKind; |
| } |
| }; |
| |
| class UnknownSpaceRegion : public MemSpaceRegion { |
| friend class MemRegionManager; |
| |
| UnknownSpaceRegion(MemRegionManager *mgr) |
| : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} |
| |
| public: |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion *R) { |
| return R->getKind() == UnknownSpaceRegionKind; |
| } |
| }; |
| |
| class StackSpaceRegion : public MemSpaceRegion { |
| virtual void anchor(); |
| |
| const StackFrameContext *SFC; |
| |
| protected: |
| StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc) |
| : MemSpaceRegion(mgr, k), SFC(sfc) { |
| assert(classof(this)); |
| assert(sfc); |
| } |
| |
| public: |
| const StackFrameContext *getStackFrame() const { return SFC; } |
| |
| void Profile(llvm::FoldingSetNodeID &ID) const override; |
| |
| static bool classof(const MemRegion *R) { |
| Kind k = R->getKind(); |
| return k >= BEGIN_STACK_MEMSPACES && k <= END_STACK_MEMSPACES; |
| } |
| }; |
| |
| class StackLocalsSpaceRegion : public StackSpaceRegion { |
| friend class MemRegionManager; |
| |
| StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) |
| : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {} |
| |
| public: |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion *R) { |
| return R->getKind() == StackLocalsSpaceRegionKind; |
| } |
| }; |
| |
| class StackArgumentsSpaceRegion : public StackSpaceRegion { |
| private: |
| friend class MemRegionManager; |
| |
| StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) |
| : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {} |
| |
| public: |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion *R) { |
| return R->getKind() == StackArgumentsSpaceRegionKind; |
| } |
| }; |
| |
| /// SubRegion - A region that subsets another larger region. Most regions |
| /// are subclasses of SubRegion. |
| class SubRegion : public MemRegion { |
| virtual void anchor(); |
| |
| protected: |
| const MemRegion* superRegion; |
| |
| SubRegion(const MemRegion *sReg, Kind k) : MemRegion(k), superRegion(sReg) { |
| assert(classof(this)); |
| assert(sReg); |
| } |
| |
| public: |
| const MemRegion* getSuperRegion() const { |
| return superRegion; |
| } |
| |
| /// getExtent - Returns the size of the region in bytes. |
| virtual DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const { |
| return UnknownVal(); |
| } |
| |
| MemRegionManager* getMemRegionManager() const override; |
| |
| bool isSubRegionOf(const MemRegion* R) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() > END_MEMSPACES; |
| } |
| }; |
| |
| //===----------------------------------------------------------------------===// |
| // MemRegion subclasses. |
| //===----------------------------------------------------------------------===// |
| |
| /// AllocaRegion - A region that represents an untyped blob of bytes created |
| /// by a call to 'alloca'. |
| class AllocaRegion : public SubRegion { |
| friend class MemRegionManager; |
| |
| // Block counter. Used to distinguish different pieces of memory allocated by |
| // alloca at the same call site. |
| unsigned Cnt; |
| |
| const Expr *Ex; |
| |
| AllocaRegion(const Expr *ex, unsigned cnt, const MemSpaceRegion *superRegion) |
| : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) { |
| assert(Ex); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex, |
| unsigned Cnt, const MemRegion *superRegion); |
| |
| public: |
| const Expr *getExpr() const { return Ex; } |
| |
| bool isBoundable() const override { return true; } |
| |
| DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; |
| |
| void Profile(llvm::FoldingSetNodeID& ID) const override; |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == AllocaRegionKind; |
| } |
| }; |
| |
| /// TypedRegion - An abstract class representing regions that are typed. |
| class TypedRegion : public SubRegion { |
| void anchor() override; |
| |
| protected: |
| TypedRegion(const MemRegion *sReg, Kind k) : SubRegion(sReg, k) { |
| assert(classof(this)); |
| } |
| |
| public: |
| virtual QualType getLocationType() const = 0; |
| |
| QualType getDesugaredLocationType(ASTContext &Context) const { |
| return getLocationType().getDesugaredType(Context); |
| } |
| |
| bool isBoundable() const override { return true; } |
| |
| static bool classof(const MemRegion* R) { |
| unsigned k = R->getKind(); |
| return k >= BEGIN_TYPED_REGIONS && k <= END_TYPED_REGIONS; |
| } |
| }; |
| |
| /// TypedValueRegion - An abstract class representing regions having a typed value. |
| class TypedValueRegion : public TypedRegion { |
| void anchor() override; |
| |
| protected: |
| TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) { |
| assert(classof(this)); |
| } |
| |
| public: |
| virtual QualType getValueType() const = 0; |
| |
| QualType getLocationType() const override { |
| // FIXME: We can possibly optimize this later to cache this value. |
| QualType T = getValueType(); |
| ASTContext &ctx = getContext(); |
| if (T->getAs<ObjCObjectType>()) |
| return ctx.getObjCObjectPointerType(T); |
| return ctx.getPointerType(getValueType()); |
| } |
| |
| QualType getDesugaredValueType(ASTContext &Context) const { |
| QualType T = getValueType(); |
| return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T; |
| } |
| |
| DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; |
| |
| static bool classof(const MemRegion* R) { |
| unsigned k = R->getKind(); |
| return k >= BEGIN_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS; |
| } |
| }; |
| |
| class CodeTextRegion : public TypedRegion { |
| void anchor() override; |
| |
| protected: |
| CodeTextRegion(const MemSpaceRegion *sreg, Kind k) : TypedRegion(sreg, k) { |
| assert(classof(this)); |
| } |
| |
| public: |
| bool isBoundable() const override { return false; } |
| |
| static bool classof(const MemRegion* R) { |
| Kind k = R->getKind(); |
| return k >= BEGIN_CODE_TEXT_REGIONS && k <= END_CODE_TEXT_REGIONS; |
| } |
| }; |
| |
| /// FunctionCodeRegion - A region that represents code texts of function. |
| class FunctionCodeRegion : public CodeTextRegion { |
| friend class MemRegionManager; |
| |
| const NamedDecl *FD; |
| |
| FunctionCodeRegion(const NamedDecl *fd, const CodeSpaceRegion* sreg) |
| : CodeTextRegion(sreg, FunctionCodeRegionKind), FD(fd) { |
| assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd)); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD, |
| const MemRegion*); |
| |
| public: |
| QualType getLocationType() const override { |
| const ASTContext &Ctx = getContext(); |
| if (const auto *D = dyn_cast<FunctionDecl>(FD)) { |
| return Ctx.getPointerType(D->getType()); |
| } |
| |
| assert(isa<ObjCMethodDecl>(FD)); |
| assert(false && "Getting the type of ObjCMethod is not supported yet"); |
| |
| // TODO: We might want to return a different type here (ex: id (*ty)(...)) |
| // depending on how it is used. |
| return {}; |
| } |
| |
| const NamedDecl *getDecl() const { |
| return FD; |
| } |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| void Profile(llvm::FoldingSetNodeID& ID) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == FunctionCodeRegionKind; |
| } |
| }; |
| |
| /// BlockCodeRegion - A region that represents code texts of blocks (closures). |
| /// Blocks are represented with two kinds of regions. BlockCodeRegions |
| /// represent the "code", while BlockDataRegions represent instances of blocks, |
| /// which correspond to "code+data". The distinction is important, because |
| /// like a closure a block captures the values of externally referenced |
| /// variables. |
| class BlockCodeRegion : public CodeTextRegion { |
| friend class MemRegionManager; |
| |
| const BlockDecl *BD; |
| AnalysisDeclContext *AC; |
| CanQualType locTy; |
| |
| BlockCodeRegion(const BlockDecl *bd, CanQualType lTy, |
| AnalysisDeclContext *ac, const CodeSpaceRegion* sreg) |
| : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) { |
| assert(bd); |
| assert(ac); |
| assert(lTy->getTypePtr()->isBlockPointerType()); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, |
| CanQualType, const AnalysisDeclContext*, |
| const MemRegion*); |
| |
| public: |
| QualType getLocationType() const override { |
| return locTy; |
| } |
| |
| const BlockDecl *getDecl() const { |
| return BD; |
| } |
| |
| AnalysisDeclContext *getAnalysisDeclContext() const { return AC; } |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| void Profile(llvm::FoldingSetNodeID& ID) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == BlockCodeRegionKind; |
| } |
| }; |
| |
| /// BlockDataRegion - A region that represents a block instance. |
| /// Blocks are represented with two kinds of regions. BlockCodeRegions |
| /// represent the "code", while BlockDataRegions represent instances of blocks, |
| /// which correspond to "code+data". The distinction is important, because |
| /// like a closure a block captures the values of externally referenced |
| /// variables. |
| class BlockDataRegion : public TypedRegion { |
| friend class MemRegionManager; |
| |
| const BlockCodeRegion *BC; |
| const LocationContext *LC; // Can be null |
| unsigned BlockCount; |
| void *ReferencedVars = nullptr; |
| void *OriginalVars = nullptr; |
| |
| BlockDataRegion(const BlockCodeRegion *bc, const LocationContext *lc, |
| unsigned count, const MemSpaceRegion *sreg) |
| : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), |
| BlockCount(count) { |
| assert(bc); |
| assert(lc); |
| assert(isa<GlobalImmutableSpaceRegion>(sreg) || |
| isa<StackLocalsSpaceRegion>(sreg) || |
| isa<UnknownSpaceRegion>(sreg)); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *, |
| const LocationContext *, unsigned, |
| const MemRegion *); |
| |
| public: |
| const BlockCodeRegion *getCodeRegion() const { return BC; } |
| |
| const BlockDecl *getDecl() const { return BC->getDecl(); } |
| |
| QualType getLocationType() const override { return BC->getLocationType(); } |
| |
| class referenced_vars_iterator { |
| const MemRegion * const *R; |
| const MemRegion * const *OriginalR; |
| |
| public: |
| explicit referenced_vars_iterator(const MemRegion * const *r, |
| const MemRegion * const *originalR) |
| : R(r), OriginalR(originalR) {} |
| |
| const VarRegion *getCapturedRegion() const { |
| return cast<VarRegion>(*R); |
| } |
| |
| const VarRegion *getOriginalRegion() const { |
| return cast<VarRegion>(*OriginalR); |
| } |
| |
| bool operator==(const referenced_vars_iterator &I) const { |
| assert((R == nullptr) == (I.R == nullptr)); |
| return I.R == R; |
| } |
| |
| bool operator!=(const referenced_vars_iterator &I) const { |
| assert((R == nullptr) == (I.R == nullptr)); |
| return I.R != R; |
| } |
| |
| referenced_vars_iterator &operator++() { |
| ++R; |
| ++OriginalR; |
| return *this; |
| } |
| }; |
| |
| /// Return the original region for a captured region, if |
| /// one exists. |
| const VarRegion *getOriginalRegion(const VarRegion *VR) const; |
| |
| referenced_vars_iterator referenced_vars_begin() const; |
| referenced_vars_iterator referenced_vars_end() const; |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| void Profile(llvm::FoldingSetNodeID& ID) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == BlockDataRegionKind; |
| } |
| |
| private: |
| void LazyInitializeReferencedVars(); |
| std::pair<const VarRegion *, const VarRegion *> |
| getCaptureRegions(const VarDecl *VD); |
| }; |
| |
| /// SymbolicRegion - A special, "non-concrete" region. Unlike other region |
| /// classes, SymbolicRegion represents a region that serves as an alias for |
| /// either a real region, a NULL pointer, etc. It essentially is used to |
| /// map the concept of symbolic values into the domain of regions. Symbolic |
| /// regions do not need to be typed. |
| class SymbolicRegion : public SubRegion { |
| friend class MemRegionManager; |
| |
| const SymbolRef sym; |
| |
| SymbolicRegion(const SymbolRef s, const MemSpaceRegion *sreg) |
| : SubRegion(sreg, SymbolicRegionKind), sym(s) { |
| // Because pointer arithmetic is represented by ElementRegion layers, |
| // the base symbol here should not contain any arithmetic. |
| assert(s && isa<SymbolData>(s)); |
| assert(s->getType()->isAnyPointerType() || |
| s->getType()->isReferenceType() || |
| s->getType()->isBlockPointerType()); |
| assert(isa<UnknownSpaceRegion>(sreg) || isa<HeapSpaceRegion>(sreg)); |
| } |
| |
| public: |
| SymbolRef getSymbol() const { return sym; } |
| |
| bool isBoundable() const override { return true; } |
| |
| DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; |
| |
| void Profile(llvm::FoldingSetNodeID& ID) const override; |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID& ID, |
| SymbolRef sym, |
| const MemRegion* superRegion); |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == SymbolicRegionKind; |
| } |
| }; |
| |
| /// StringRegion - Region associated with a StringLiteral. |
| class StringRegion : public TypedValueRegion { |
| friend class MemRegionManager; |
| |
| const StringLiteral *Str; |
| |
| StringRegion(const StringLiteral *str, const GlobalInternalSpaceRegion *sreg) |
| : TypedValueRegion(sreg, StringRegionKind), Str(str) { |
| assert(str); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID &ID, |
| const StringLiteral *Str, |
| const MemRegion *superRegion); |
| |
| public: |
| const StringLiteral *getStringLiteral() const { return Str; } |
| |
| QualType getValueType() const override { return Str->getType(); } |
| |
| DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; |
| |
| bool isBoundable() const override { return false; } |
| |
| void Profile(llvm::FoldingSetNodeID& ID) const override { |
| ProfileRegion(ID, Str, superRegion); |
| } |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == StringRegionKind; |
| } |
| }; |
| |
| /// The region associated with an ObjCStringLiteral. |
| class ObjCStringRegion : public TypedValueRegion { |
| friend class MemRegionManager; |
| |
| const ObjCStringLiteral *Str; |
| |
| ObjCStringRegion(const ObjCStringLiteral *str, |
| const GlobalInternalSpaceRegion *sreg) |
| : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) { |
| assert(str); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID &ID, |
| const ObjCStringLiteral *Str, |
| const MemRegion *superRegion); |
| |
| public: |
| const ObjCStringLiteral *getObjCStringLiteral() const { return Str; } |
| |
| QualType getValueType() const override { return Str->getType(); } |
| |
| bool isBoundable() const override { return false; } |
| |
| void Profile(llvm::FoldingSetNodeID& ID) const override { |
| ProfileRegion(ID, Str, superRegion); |
| } |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == ObjCStringRegionKind; |
| } |
| }; |
| |
| /// CompoundLiteralRegion - A memory region representing a compound literal. |
| /// Compound literals are essentially temporaries that are stack allocated |
| /// or in the global constant pool. |
| class CompoundLiteralRegion : public TypedValueRegion { |
| friend class MemRegionManager; |
| |
| const CompoundLiteralExpr *CL; |
| |
| CompoundLiteralRegion(const CompoundLiteralExpr *cl, |
| const MemSpaceRegion *sReg) |
| : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) { |
| assert(cl); |
| assert(isa<GlobalInternalSpaceRegion>(sReg) || |
| isa<StackLocalsSpaceRegion>(sReg)); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID& ID, |
| const CompoundLiteralExpr *CL, |
| const MemRegion* superRegion); |
| |
| public: |
| QualType getValueType() const override { return CL->getType(); } |
| |
| bool isBoundable() const override { return !CL->isFileScope(); } |
| |
| void Profile(llvm::FoldingSetNodeID& ID) const override; |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| const CompoundLiteralExpr *getLiteralExpr() const { return CL; } |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == CompoundLiteralRegionKind; |
| } |
| }; |
| |
| class DeclRegion : public TypedValueRegion { |
| protected: |
| const ValueDecl *D; |
| |
| DeclRegion(const ValueDecl *d, const MemRegion *sReg, Kind k) |
| : TypedValueRegion(sReg, k), D(d) { |
| assert(classof(this)); |
| assert(d && d->isCanonicalDecl()); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D, |
| const MemRegion* superRegion, Kind k); |
| |
| public: |
| const ValueDecl *getDecl() const { return D; } |
| void Profile(llvm::FoldingSetNodeID& ID) const override; |
| |
| static bool classof(const MemRegion* R) { |
| unsigned k = R->getKind(); |
| return k >= BEGIN_DECL_REGIONS && k <= END_DECL_REGIONS; |
| } |
| }; |
| |
| class VarRegion : public DeclRegion { |
| friend class MemRegionManager; |
| |
| // Constructors and private methods. |
| VarRegion(const VarDecl *vd, const MemRegion *sReg) |
| : DeclRegion(vd, sReg, VarRegionKind) { |
| // VarRegion appears in unknown space when it's a block variable as seen |
| // from a block using it, when this block is analyzed at top-level. |
| // Other block variables appear within block data regions, |
| // which, unlike everything else on this list, are not memory spaces. |
| assert(isa<GlobalsSpaceRegion>(sReg) || isa<StackSpaceRegion>(sReg) || |
| isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg)); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD, |
| const MemRegion *superRegion) { |
| DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); |
| } |
| |
| public: |
| void Profile(llvm::FoldingSetNodeID& ID) const override; |
| |
| const VarDecl *getDecl() const { return cast<VarDecl>(D); } |
| |
| const StackFrameContext *getStackFrame() const; |
| |
| QualType getValueType() const override { |
| // FIXME: We can cache this if needed. |
| return getDecl()->getType(); |
| } |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| bool canPrintPrettyAsExpr() const override; |
| |
| void printPrettyAsExpr(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == VarRegionKind; |
| } |
| }; |
| |
| /// CXXThisRegion - Represents the region for the implicit 'this' parameter |
| /// in a call to a C++ method. This region doesn't represent the object |
| /// referred to by 'this', but rather 'this' itself. |
| class CXXThisRegion : public TypedValueRegion { |
| friend class MemRegionManager; |
| |
| CXXThisRegion(const PointerType *thisPointerTy, |
| const StackArgumentsSpaceRegion *sReg) |
| : TypedValueRegion(sReg, CXXThisRegionKind), |
| ThisPointerTy(thisPointerTy) { |
| assert(ThisPointerTy->getPointeeType()->getAsCXXRecordDecl() && |
| "Invalid region type!"); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID &ID, |
| const PointerType *PT, |
| const MemRegion *sReg); |
| |
| public: |
| void Profile(llvm::FoldingSetNodeID &ID) const override; |
| |
| QualType getValueType() const override { |
| return QualType(ThisPointerTy, 0); |
| } |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == CXXThisRegionKind; |
| } |
| |
| private: |
| const PointerType *ThisPointerTy; |
| }; |
| |
| class FieldRegion : public DeclRegion { |
| friend class MemRegionManager; |
| |
| FieldRegion(const FieldDecl *fd, const SubRegion* sReg) |
| : DeclRegion(fd, sReg, FieldRegionKind) {} |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD, |
| const MemRegion* superRegion) { |
| DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); |
| } |
| |
| public: |
| const FieldDecl *getDecl() const { return cast<FieldDecl>(D); } |
| |
| QualType getValueType() const override { |
| // FIXME: We can cache this if needed. |
| return getDecl()->getType(); |
| } |
| |
| DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| bool canPrintPretty() const override; |
| void printPretty(raw_ostream &os) const override; |
| bool canPrintPrettyAsExpr() const override; |
| void printPrettyAsExpr(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == FieldRegionKind; |
| } |
| }; |
| |
| class ObjCIvarRegion : public DeclRegion { |
| friend class MemRegionManager; |
| |
| ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg); |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd, |
| const MemRegion* superRegion); |
| |
| public: |
| const ObjCIvarDecl *getDecl() const; |
| QualType getValueType() const override; |
| |
| bool canPrintPrettyAsExpr() const override; |
| void printPrettyAsExpr(raw_ostream &os) const override; |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == ObjCIvarRegionKind; |
| } |
| }; |
| |
| //===----------------------------------------------------------------------===// |
| // Auxiliary data classes for use with MemRegions. |
| //===----------------------------------------------------------------------===// |
| |
| class RegionRawOffset { |
| friend class ElementRegion; |
| |
| const MemRegion *Region; |
| CharUnits Offset; |
| |
| RegionRawOffset(const MemRegion* reg, CharUnits offset = CharUnits::Zero()) |
| : Region(reg), Offset(offset) {} |
| |
| public: |
| // FIXME: Eventually support symbolic offsets. |
| CharUnits getOffset() const { return Offset; } |
| const MemRegion *getRegion() const { return Region; } |
| |
| void dumpToStream(raw_ostream &os) const; |
| void dump() const; |
| }; |
| |
| /// ElementRegion is used to represent both array elements and casts. |
| class ElementRegion : public TypedValueRegion { |
| friend class MemRegionManager; |
| |
| QualType ElementType; |
| NonLoc Index; |
| |
| ElementRegion(QualType elementType, NonLoc Idx, const SubRegion *sReg) |
| : TypedValueRegion(sReg, ElementRegionKind), ElementType(elementType), |
| Index(Idx) { |
| assert((!Idx.getAs<nonloc::ConcreteInt>() || |
| Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) && |
| "The index must be signed"); |
| assert(!elementType.isNull() && !elementType->isVoidType() && |
| "Invalid region type!"); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType, |
| SVal Idx, const MemRegion* superRegion); |
| |
| public: |
| NonLoc getIndex() const { return Index; } |
| |
| QualType getValueType() const override { return ElementType; } |
| |
| QualType getElementType() const { return ElementType; } |
| |
| /// Compute the offset within the array. The array might also be a subobject. |
| RegionRawOffset getAsArrayOffset() const; |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| void Profile(llvm::FoldingSetNodeID& ID) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == ElementRegionKind; |
| } |
| }; |
| |
| // C++ temporary object associated with an expression. |
| class CXXTempObjectRegion : public TypedValueRegion { |
| friend class MemRegionManager; |
| |
| Expr const *Ex; |
| |
| CXXTempObjectRegion(Expr const *E, MemSpaceRegion const *sReg) |
| : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) { |
| assert(E); |
| assert(isa<StackLocalsSpaceRegion>(sReg) || |
| isa<GlobalInternalSpaceRegion>(sReg)); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID &ID, |
| Expr const *E, const MemRegion *sReg); |
| |
| public: |
| const Expr *getExpr() const { return Ex; } |
| |
| QualType getValueType() const override { return Ex->getType(); } |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| void Profile(llvm::FoldingSetNodeID &ID) const override; |
| |
| static bool classof(const MemRegion* R) { |
| return R->getKind() == CXXTempObjectRegionKind; |
| } |
| }; |
| |
| // CXXBaseObjectRegion represents a base object within a C++ object. It is |
| // identified by the base class declaration and the region of its parent object. |
| class CXXBaseObjectRegion : public TypedValueRegion { |
| friend class MemRegionManager; |
| |
| llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data; |
| |
| CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual, |
| const SubRegion *SReg) |
| : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) { |
| assert(RD); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD, |
| bool IsVirtual, const MemRegion *SReg); |
| |
| public: |
| const CXXRecordDecl *getDecl() const { return Data.getPointer(); } |
| bool isVirtual() const { return Data.getInt(); } |
| |
| QualType getValueType() const override; |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| void Profile(llvm::FoldingSetNodeID &ID) const override; |
| |
| bool canPrintPrettyAsExpr() const override; |
| |
| void printPrettyAsExpr(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion *region) { |
| return region->getKind() == CXXBaseObjectRegionKind; |
| } |
| }; |
| |
| // CXXDerivedObjectRegion represents a derived-class object that surrounds |
| // a C++ object. It is identified by the derived class declaration and the |
| // region of its parent object. It is a bit counter-intuitive (but not otherwise |
| // unseen) that this region represents a larger segment of memory that its |
| // super-region. |
| class CXXDerivedObjectRegion : public TypedValueRegion { |
| friend class MemRegionManager; |
| |
| const CXXRecordDecl *DerivedD; |
| |
| CXXDerivedObjectRegion(const CXXRecordDecl *DerivedD, const SubRegion *SReg) |
| : TypedValueRegion(SReg, CXXDerivedObjectRegionKind), DerivedD(DerivedD) { |
| assert(DerivedD); |
| // In case of a concrete region, it should always be possible to model |
| // the base-to-derived cast by undoing a previous derived-to-base cast, |
| // otherwise the cast is most likely ill-formed. |
| assert(SReg->getSymbolicBase() && |
| "Should have unwrapped a base region instead!"); |
| } |
| |
| static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD, |
| const MemRegion *SReg); |
| |
| public: |
| const CXXRecordDecl *getDecl() const { return DerivedD; } |
| |
| QualType getValueType() const override; |
| |
| void dumpToStream(raw_ostream &os) const override; |
| |
| void Profile(llvm::FoldingSetNodeID &ID) const override; |
| |
| bool canPrintPrettyAsExpr() const override; |
| |
| void printPrettyAsExpr(raw_ostream &os) const override; |
| |
| static bool classof(const MemRegion *region) { |
| return region->getKind() == CXXDerivedObjectRegionKind; |
| } |
| }; |
| |
| template<typename RegionTy> |
| const RegionTy* MemRegion::getAs() const { |
| if (const auto *RT = dyn_cast<RegionTy>(this)) |
| return RT; |
| |
| return nullptr; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // MemRegionManager - Factory object for creating regions. |
| //===----------------------------------------------------------------------===// |
| |
| class MemRegionManager { |
| ASTContext &C; |
| llvm::BumpPtrAllocator& A; |
| llvm::FoldingSet<MemRegion> Regions; |
| |
| GlobalInternalSpaceRegion *InternalGlobals = nullptr; |
| GlobalSystemSpaceRegion *SystemGlobals = nullptr; |
| GlobalImmutableSpaceRegion *ImmutableGlobals = nullptr; |
| |
| llvm::DenseMap<const StackFrameContext *, StackLocalsSpaceRegion *> |
| StackLocalsSpaceRegions; |
| llvm::DenseMap<const StackFrameContext *, StackArgumentsSpaceRegion *> |
| StackArgumentsSpaceRegions; |
| llvm::DenseMap<const CodeTextRegion *, StaticGlobalSpaceRegion *> |
| StaticsGlobalSpaceRegions; |
| |
| HeapSpaceRegion *heap = nullptr; |
| UnknownSpaceRegion *unknown = nullptr; |
| CodeSpaceRegion *code = nullptr; |
| |
| public: |
| MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a) : C(c), A(a) {} |
| ~MemRegionManager(); |
| |
| ASTContext &getContext() { return C; } |
| |
| llvm::BumpPtrAllocator &getAllocator() { return A; } |
| |
| /// getStackLocalsRegion - Retrieve the memory region associated with the |
| /// specified stack frame. |
| const StackLocalsSpaceRegion * |
| getStackLocalsRegion(const StackFrameContext *STC); |
| |
| /// getStackArgumentsRegion - Retrieve the memory region associated with |
| /// function/method arguments of the specified stack frame. |
| const StackArgumentsSpaceRegion * |
| getStackArgumentsRegion(const StackFrameContext *STC); |
| |
| /// getGlobalsRegion - Retrieve the memory region associated with |
| /// global variables. |
| const GlobalsSpaceRegion *getGlobalsRegion( |
| MemRegion::Kind K = MemRegion::GlobalInternalSpaceRegionKind, |
| const CodeTextRegion *R = nullptr); |
| |
| /// getHeapRegion - Retrieve the memory region associated with the |
| /// generic "heap". |
| const HeapSpaceRegion *getHeapRegion(); |
| |
| /// getUnknownRegion - Retrieve the memory region associated with unknown |
| /// memory space. |
| const UnknownSpaceRegion *getUnknownRegion(); |
| |
| const CodeSpaceRegion *getCodeRegion(); |
| |
| /// getAllocaRegion - Retrieve a region associated with a call to alloca(). |
| const AllocaRegion *getAllocaRegion(const Expr *Ex, unsigned Cnt, |
| const LocationContext *LC); |
| |
| /// getCompoundLiteralRegion - Retrieve the region associated with a |
| /// given CompoundLiteral. |
| const CompoundLiteralRegion* |
| getCompoundLiteralRegion(const CompoundLiteralExpr *CL, |
| const LocationContext *LC); |
| |
| /// getCXXThisRegion - Retrieve the [artificial] region associated with the |
| /// parameter 'this'. |
| const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy, |
| const LocationContext *LC); |
| |
| /// Retrieve or create a "symbolic" memory region. |
| const SymbolicRegion* getSymbolicRegion(SymbolRef Sym); |
| |
| /// Return a unique symbolic region belonging to heap memory space. |
| const SymbolicRegion *getSymbolicHeapRegion(SymbolRef sym); |
| |
| const StringRegion *getStringRegion(const StringLiteral *Str); |
| |
| const ObjCStringRegion *getObjCStringRegion(const ObjCStringLiteral *Str); |
| |
| /// getVarRegion - Retrieve or create the memory region associated with |
| /// a specified VarDecl and LocationContext. |
| const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC); |
| |
| /// getVarRegion - Retrieve or create the memory region associated with |
| /// a specified VarDecl and super region. |
| const VarRegion *getVarRegion(const VarDecl *D, const MemRegion *superR); |
| |
| /// getElementRegion - Retrieve the memory region associated with the |
| /// associated element type, index, and super region. |
| const ElementRegion *getElementRegion(QualType elementType, NonLoc Idx, |
| const SubRegion *superRegion, |
| ASTContext &Ctx); |
| |
| const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, |
| const SubRegion *superRegion) { |
| return getElementRegion(ER->getElementType(), ER->getIndex(), |
| superRegion, ER->getContext()); |
| } |
| |
| /// getFieldRegion - Retrieve or create the memory region associated with |
| /// a specified FieldDecl. 'superRegion' corresponds to the containing |
| /// memory region (which typically represents the memory representing |
| /// a structure or class). |
| const FieldRegion *getFieldRegion(const FieldDecl *fd, |
| const SubRegion* superRegion); |
| |
| const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, |
| const SubRegion *superRegion) { |
| return getFieldRegion(FR->getDecl(), superRegion); |
| } |
| |
| /// getObjCIvarRegion - Retrieve or create the memory region associated with |
| /// a specified Objective-c instance variable. 'superRegion' corresponds |
| /// to the containing region (which typically represents the Objective-C |
| /// object). |
| const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl *ivd, |
| const SubRegion* superRegion); |
| |
| const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex, |
| LocationContext const *LC); |
| |
| /// Create a CXXBaseObjectRegion with the given base class for region |
| /// \p Super. |
| /// |
| /// The type of \p Super is assumed be a class deriving from \p BaseClass. |
| const CXXBaseObjectRegion * |
| getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const SubRegion *Super, |
| bool IsVirtual); |
| |
| /// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different |
| /// super region. |
| const CXXBaseObjectRegion * |
| getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg, |
| const SubRegion *superRegion) { |
| return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion, |
| baseReg->isVirtual()); |
| } |
| |
| /// Create a CXXDerivedObjectRegion with the given derived class for region |
| /// \p Super. This should not be used for casting an existing |
| /// CXXBaseObjectRegion back to the derived type; instead, CXXBaseObjectRegion |
| /// should be removed. |
| const CXXDerivedObjectRegion * |
| getCXXDerivedObjectRegion(const CXXRecordDecl *BaseClass, |
| const SubRegion *Super); |
| |
| const FunctionCodeRegion *getFunctionCodeRegion(const NamedDecl *FD); |
| const BlockCodeRegion *getBlockCodeRegion(const BlockDecl *BD, |
| CanQualType locTy, |
| AnalysisDeclContext *AC); |
| |
| /// getBlockDataRegion - Get the memory region associated with an instance |
| /// of a block. Unlike many other MemRegions, the LocationContext* |
| /// argument is allowed to be NULL for cases where we have no known |
| /// context. |
| const BlockDataRegion *getBlockDataRegion(const BlockCodeRegion *bc, |
| const LocationContext *lc, |
| unsigned blockCount); |
| |
| /// Create a CXXTempObjectRegion for temporaries which are lifetime-extended |
| /// by static references. This differs from getCXXTempObjectRegion in the |
| /// super-region used. |
| const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex); |
| |
| private: |
| template <typename RegionTy, typename SuperTy, |
| typename Arg1Ty> |
| RegionTy* getSubRegion(const Arg1Ty arg1, |
| const SuperTy* superRegion); |
| |
| template <typename RegionTy, typename SuperTy, |
| typename Arg1Ty, typename Arg2Ty> |
| RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, |
| const SuperTy* superRegion); |
| |
| template <typename RegionTy, typename SuperTy, |
| typename Arg1Ty, typename Arg2Ty, typename Arg3Ty> |
| RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, |
| const Arg3Ty arg3, |
| const SuperTy* superRegion); |
| |
| template <typename REG> |
| const REG* LazyAllocate(REG*& region); |
| |
| template <typename REG, typename ARG> |
| const REG* LazyAllocate(REG*& region, ARG a); |
| }; |
| |
| //===----------------------------------------------------------------------===// |
| // Out-of-line member definitions. |
| //===----------------------------------------------------------------------===// |
| |
| inline ASTContext &MemRegion::getContext() const { |
| return getMemRegionManager()->getContext(); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Means for storing region/symbol handling traits. |
| //===----------------------------------------------------------------------===// |
| |
| /// Information about invalidation for a particular region/symbol. |
| class RegionAndSymbolInvalidationTraits { |
| using StorageTypeForKinds = unsigned char; |
| |
| llvm::DenseMap<const MemRegion *, StorageTypeForKinds> MRTraitsMap; |
| llvm::DenseMap<SymbolRef, StorageTypeForKinds> SymTraitsMap; |
| |
| using const_region_iterator = |
| llvm::DenseMap<const MemRegion *, StorageTypeForKinds>::const_iterator; |
| using const_symbol_iterator = |
| llvm::DenseMap<SymbolRef, StorageTypeForKinds>::const_iterator; |
| |
| public: |
| /// Describes different invalidation traits. |
| enum InvalidationKinds { |
| /// Tells that a region's contents is not changed. |
| TK_PreserveContents = 0x1, |
| |
| /// Suppress pointer-escaping of a region. |
| TK_SuppressEscape = 0x2, |
| |
| // Do not invalidate super region. |
| TK_DoNotInvalidateSuperRegion = 0x4, |
| |
| /// When applied to a MemSpaceRegion, indicates the entire memory space |
| /// should be invalidated. |
| TK_EntireMemSpace = 0x8 |
| |
| // Do not forget to extend StorageTypeForKinds if number of traits exceed |
| // the number of bits StorageTypeForKinds can store. |
| }; |
| |
| void setTrait(SymbolRef Sym, InvalidationKinds IK); |
| void setTrait(const MemRegion *MR, InvalidationKinds IK); |
| bool hasTrait(SymbolRef Sym, InvalidationKinds IK) const; |
| bool hasTrait(const MemRegion *MR, InvalidationKinds IK) const; |
| }; |
| |
| //===----------------------------------------------------------------------===// |
| // Pretty-printing regions. |
| //===----------------------------------------------------------------------===// |
| inline raw_ostream &operator<<(raw_ostream &os, const MemRegion *R) { |
| R->dumpToStream(os); |
| return os; |
| } |
| |
| } // namespace ento |
| |
| } // namespace clang |
| |
| #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H |