llvm-project/clang/lib/Analysis/MemRegion.cpp

457 lines
13 KiB
C++
Raw Normal View History

//== MemRegion.cpp - Abstract memory regions for static analysis --*- C++ -*--//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines MemRegion and its subclasses. MemRegion defines a
// partially-typed abstraction of memory useful for path-sensitive dataflow
// analyses.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/raw_ostream.h"
#include "clang/Analysis/PathSensitive/MemRegion.h"
using namespace clang;
MemRegion::~MemRegion() {}
bool SubRegion::isSubRegionOf(const MemRegion* R) const {
const MemRegion* r = getSuperRegion();
while (r != 0) {
if (r == R)
return true;
if (const SubRegion* sr = dyn_cast<SubRegion>(r))
r = sr->getSuperRegion();
else
break;
}
return false;
}
void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddInteger((unsigned)getKind());
}
void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const StringLiteral* Str,
const MemRegion* superRegion) {
ID.AddInteger((unsigned) StringRegionKind);
ID.AddPointer(Str);
ID.AddPointer(superRegion);
}
void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const Expr* Ex, unsigned cnt) {
ID.AddInteger((unsigned) AllocaRegionKind);
ID.AddPointer(Ex);
ID.AddInteger(cnt);
}
void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ProfileRegion(ID, Ex, Cnt);
}
void AnonTypedRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T,
const MemRegion* superRegion) {
ID.AddInteger((unsigned) AnonTypedRegionKind);
ID.Add(T);
ID.AddPointer(superRegion);
}
void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const {
CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion);
}
void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const CompoundLiteralExpr* CL,
const MemRegion* superRegion) {
ID.AddInteger((unsigned) CompoundLiteralRegionKind);
ID.AddPointer(CL);
ID.AddPointer(superRegion);
}
void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
const MemRegion* superRegion, Kind k) {
ID.AddInteger((unsigned) k);
ID.AddPointer(D);
ID.AddPointer(superRegion);
}
void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const {
DeclRegion::ProfileRegion(ID, D, superRegion, getKind());
}
void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym) {
ID.AddInteger((unsigned) MemRegion::SymbolicRegionKind);
ID.Add(sym);
}
void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const {
SymbolicRegion::ProfileRegion(ID, sym);
}
void ElementRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SVal Idx,
const MemRegion* superRegion) {
ID.AddInteger(MemRegion::ElementRegionKind);
ID.AddPointer(superRegion);
Idx.Profile(ID);
}
void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ElementRegion::ProfileRegion(ID, Index, superRegion);
}
//===----------------------------------------------------------------------===//
// getLValueType() and getRValueType()
//===----------------------------------------------------------------------===//
QualType SymbolicRegion::getRValueType(ASTContext& C) const {
const SymbolData& data = SymMgr.getSymbolData(sym);
// Get the type of the symbol.
QualType T = data.getType(C);
// Only when the symbol has pointer type it can have a symbolic region
// associated with it.
PointerType* PTy = cast<PointerType>(T.getTypePtr()->getDesugaredType());
// The type of the symbolic region is the pointee type of the symbol.
return PTy->getPointeeType();
}
MemRegion: - Overhauled the notion of "types" for TypedRegions. We now distinguish between the "lvalue" of a region (via getLValueRegion()) and the "rvalue" of a region (va getRValueRegion()). Since a region represents a chunk of memory it has both, but we were conflating these concepts in some cases, leading to some insidious bugs. - Removed AnonPointeeType, partially because it is unused and because it doesn't have a clear notion of lvalue vs rvalue type. We can add it back once there is a need for it and we can resolve its role with these concepts. StoreManager: - Overhauled StoreManager::CastRegion. It expects an *lvalue* type for a region. This is actually what motivated the overhaul to the MemRegion type mechanism. It also no longer returns an SVal; we can just return a MemRegion*. - BasicStoreManager::CastRegion now overlays an "AnonTypedRegion" for pointer-pointer casts. This matches with the MemRegion changes. - Similar changes to RegionStore, except I've added a bunch of FIXMEs where it wasn't 100% clear where we should use TypedRegion::getRValueRegion() or TypedRegion::getLValueRegion(). AuditCFNumberCreate check: - Now blasts through AnonTypedRegions that may layer the original memory region, thus checking if the actually memory block is of the appropriate type. This change was needed to work with the changes to StoreManager::CastRegion. GRExprEngine::VisitCast: - Conform to the new interface of StoreManager::CastRegion. Tests: - None of the analysis tests fail now for using the "basic store". - Disabled the tests 'array-struct.c' and 'rdar-6442306-1.m' pending further testing and bug fixing. llvm-svn: 60995
2008-12-14 05:49:13 +08:00
QualType ElementRegion::getRValueType(ASTContext& C) const {
// Strip off typedefs from the ArrayRegion's RvalueType.
QualType T = getArrayRegion()->getRValueType(C)->getDesugaredType();
if (ArrayType* AT = dyn_cast<ArrayType>(T.getTypePtr()))
return AT->getElementType();
// If the RValueType of the array region isn't an ArrayType, then essentially
// the element's
return T;
}
MemRegion: - Overhauled the notion of "types" for TypedRegions. We now distinguish between the "lvalue" of a region (via getLValueRegion()) and the "rvalue" of a region (va getRValueRegion()). Since a region represents a chunk of memory it has both, but we were conflating these concepts in some cases, leading to some insidious bugs. - Removed AnonPointeeType, partially because it is unused and because it doesn't have a clear notion of lvalue vs rvalue type. We can add it back once there is a need for it and we can resolve its role with these concepts. StoreManager: - Overhauled StoreManager::CastRegion. It expects an *lvalue* type for a region. This is actually what motivated the overhaul to the MemRegion type mechanism. It also no longer returns an SVal; we can just return a MemRegion*. - BasicStoreManager::CastRegion now overlays an "AnonTypedRegion" for pointer-pointer casts. This matches with the MemRegion changes. - Similar changes to RegionStore, except I've added a bunch of FIXMEs where it wasn't 100% clear where we should use TypedRegion::getRValueRegion() or TypedRegion::getLValueRegion(). AuditCFNumberCreate check: - Now blasts through AnonTypedRegions that may layer the original memory region, thus checking if the actually memory block is of the appropriate type. This change was needed to work with the changes to StoreManager::CastRegion. GRExprEngine::VisitCast: - Conform to the new interface of StoreManager::CastRegion. Tests: - None of the analysis tests fail now for using the "basic store". - Disabled the tests 'array-struct.c' and 'rdar-6442306-1.m' pending further testing and bug fixing. llvm-svn: 60995
2008-12-14 05:49:13 +08:00
QualType StringRegion::getRValueType(ASTContext& C) const {
return Str->getType();
}
//===----------------------------------------------------------------------===//
// Region pretty-printing.
//===----------------------------------------------------------------------===//
std::string MemRegion::getString() const {
std::string s;
llvm::raw_string_ostream os(s);
print(os);
return os.str();
}
void MemRegion::print(llvm::raw_ostream& os) const {
os << "<Unknown Region>";
}
void AllocaRegion::print(llvm::raw_ostream& os) const {
os << "alloca{" << (void*) Ex << ',' << Cnt << '}';
}
void AnonTypedRegion::print(llvm::raw_ostream& os) const {
os << "anon_type{" << T.getAsString() << ',';
getSuperRegion()->print(os);
os << '}';
}
void VarRegion::print(llvm::raw_ostream& os) const {
os << cast<VarDecl>(D)->getNameAsString();
}
void SymbolicRegion::print(llvm::raw_ostream& os) const {
os << "SymRegion-";
sym.print(os);
}
void FieldRegion::print(llvm::raw_ostream& os) const {
superRegion->print(os);
os << "->" << getDecl()->getNameAsString();
}
void ElementRegion::print(llvm::raw_ostream& os) const {
superRegion->print(os);
os << '['; Index.print(os); os << ']';
}
void CompoundLiteralRegion::print(llvm::raw_ostream& os) const {
// FIXME: More elaborate pretty-printing.
os << "{ " << (void*) CL << " }";
}
void StringRegion::print(llvm::raw_ostream& os) const {
Str->printPretty(os);
}
//===----------------------------------------------------------------------===//
// MemRegionManager methods.
//===----------------------------------------------------------------------===//
MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) {
if (!region) {
region = (MemSpaceRegion*) A.Allocate<MemSpaceRegion>();
new (region) MemSpaceRegion();
}
return region;
}
MemSpaceRegion* MemRegionManager::getStackRegion() {
return LazyAllocate(stack);
}
MemSpaceRegion* MemRegionManager::getGlobalsRegion() {
return LazyAllocate(globals);
}
MemSpaceRegion* MemRegionManager::getHeapRegion() {
return LazyAllocate(heap);
}
MemSpaceRegion* MemRegionManager::getUnknownRegion() {
return LazyAllocate(unknown);
}
bool MemRegionManager::onStack(const MemRegion* R) {
while (const SubRegion* SR = dyn_cast<SubRegion>(R))
R = SR->getSuperRegion();
return (R != 0) && (R == stack);
}
bool MemRegionManager::onHeap(const MemRegion* R) {
while (const SubRegion* SR = dyn_cast<SubRegion>(R))
R = SR->getSuperRegion();
return (R != 0) && (R == heap);
}
StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) {
llvm::FoldingSetNodeID ID;
MemSpaceRegion* GlobalsR = getGlobalsRegion();
StringRegion::ProfileRegion(ID, Str, GlobalsR);
void* InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
StringRegion* R = cast_or_null<StringRegion>(data);
if (!R) {
R = (StringRegion*) A.Allocate<StringRegion>();
new (R) StringRegion(Str, GlobalsR);
Regions.InsertNode(R, InsertPos);
}
return R;
}
VarRegion* MemRegionManager::getVarRegion(const VarDecl* d) {
const MemRegion* superRegion = d->hasLocalStorage() ? getStackRegion()
: getGlobalsRegion();
llvm::FoldingSetNodeID ID;
DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::VarRegionKind);
void* InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
VarRegion* R = cast_or_null<VarRegion>(data);
if (!R) {
R = (VarRegion*) A.Allocate<VarRegion>();
new (R) VarRegion(d, superRegion);
Regions.InsertNode(R, InsertPos);
}
return R;
}
CompoundLiteralRegion*
MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) {
// Is this compound literal allocated on the stack or is part of the
// global constant pool?
const MemRegion* superRegion = CL->isFileScope() ?
getGlobalsRegion() : getStackRegion();
// Profile the compound literal.
llvm::FoldingSetNodeID ID;
CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion);
void* InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
CompoundLiteralRegion* R = cast_or_null<CompoundLiteralRegion>(data);
if (!R) {
R = (CompoundLiteralRegion*) A.Allocate<CompoundLiteralRegion>();
new (R) CompoundLiteralRegion(CL, superRegion);
Regions.InsertNode(R, InsertPos);
}
return R;
}
ElementRegion*
MemRegionManager::getElementRegion(SVal Idx, const TypedRegion* superRegion){
llvm::FoldingSetNodeID ID;
ElementRegion::ProfileRegion(ID, Idx, superRegion);
void* InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
ElementRegion* R = cast_or_null<ElementRegion>(data);
if (!R) {
R = (ElementRegion*) A.Allocate<ElementRegion>();
new (R) ElementRegion(Idx, superRegion);
Regions.InsertNode(R, InsertPos);
}
return R;
}
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
SymbolicRegion* MemRegionManager::getSymbolicRegion(const SymbolRef sym,
const SymbolManager& mgr) {
llvm::FoldingSetNodeID ID;
SymbolicRegion::ProfileRegion(ID, sym);
void* InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
SymbolicRegion* R = cast_or_null<SymbolicRegion>(data);
if (!R) {
R = (SymbolicRegion*) A.Allocate<SymbolicRegion>();
// SymbolicRegion's storage class is usually unknown.
new (R) SymbolicRegion(sym, mgr, getUnknownRegion());
Regions.InsertNode(R, InsertPos);
}
return R;
}
FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d,
const MemRegion* superRegion) {
llvm::FoldingSetNodeID ID;
DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::FieldRegionKind);
void* InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
FieldRegion* R = cast_or_null<FieldRegion>(data);
if (!R) {
R = (FieldRegion*) A.Allocate<FieldRegion>();
new (R) FieldRegion(d, superRegion);
Regions.InsertNode(R, InsertPos);
}
return R;
}
ObjCIvarRegion*
MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
const MemRegion* superRegion) {
llvm::FoldingSetNodeID ID;
DeclRegion::ProfileRegion(ID, d, superRegion, MemRegion::ObjCIvarRegionKind);
void* InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
ObjCIvarRegion* R = cast_or_null<ObjCIvarRegion>(data);
if (!R) {
2008-10-06 11:03:33 +08:00
R = (ObjCIvarRegion*) A.Allocate<ObjCIvarRegion>();
new (R) ObjCIvarRegion(d, superRegion);
Regions.InsertNode(R, InsertPos);
}
return R;
}
ObjCObjectRegion*
MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d,
const MemRegion* superRegion) {
llvm::FoldingSetNodeID ID;
DeclRegion::ProfileRegion(ID, d, superRegion,
MemRegion::ObjCObjectRegionKind);
void* InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
ObjCObjectRegion* R = cast_or_null<ObjCObjectRegion>(data);
if (!R) {
R = (ObjCObjectRegion*) A.Allocate<ObjCObjectRegion>();
new (R) ObjCObjectRegion(d, superRegion);
Regions.InsertNode(R, InsertPos);
}
return R;
}
AnonTypedRegion*
MemRegionManager::getAnonTypedRegion(QualType t, const MemRegion* superRegion) {
llvm::FoldingSetNodeID ID;
AnonTypedRegion::ProfileRegion(ID, t, superRegion);
void* InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
AnonTypedRegion* R = cast_or_null<AnonTypedRegion>(data);
if (!R) {
R = (AnonTypedRegion*) A.Allocate<AnonTypedRegion>();
new (R) AnonTypedRegion(t, superRegion);
Regions.InsertNode(R, InsertPos);
}
return R;
}
AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt) {
llvm::FoldingSetNodeID ID;
AllocaRegion::ProfileRegion(ID, E, cnt);
void* InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
AllocaRegion* R = cast_or_null<AllocaRegion>(data);
if (!R) {
R = (AllocaRegion*) A.Allocate<AllocaRegion>();
new (R) AllocaRegion(E, cnt, getStackRegion());
Regions.InsertNode(R, InsertPos);
}
return R;
}
bool MemRegionManager::hasStackStorage(const MemRegion* R) {
// Only subregions can have stack storage.
const SubRegion* SR = dyn_cast<SubRegion>(R);
if (!SR)
return false;
MemSpaceRegion* S = getStackRegion();
while (SR) {
R = SR->getSuperRegion();
if (R == S)
return true;
SR = dyn_cast<SubRegion>(R);
}
return false;
}