Newer
Older
Ted Kremenek
committed
//== 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"
#include "clang/Analysis/PathSensitive/ValueManager.h"
Ted Kremenek
committed
using namespace clang;
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// Basic methods.
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
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;
}
MemRegionManager* SubRegion::getMemRegionManager() const {
const SubRegion* r = this;
do {
const MemRegion *superRegion = r->getSuperRegion();
if (const SubRegion *sr = dyn_cast<SubRegion>(superRegion)) {
r = sr;
continue;
}
return superRegion->getMemRegionManager();
} while (1);
}
Ted Kremenek
committed
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,
Ted Kremenek
committed
const Expr* Ex, unsigned cnt,
const MemRegion *) {
ID.AddInteger((unsigned) AllocaRegionKind);
ID.AddPointer(Ex);
ID.AddInteger(cnt);
}
void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
Ted Kremenek
committed
ProfileRegion(ID, Ex, Cnt, superRegion);
}
Ted Kremenek
committed
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);
}
Ted Kremenek
committed
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());
}
Ted Kremenek
committed
void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
const MemRegion *sreg) {
ID.AddInteger((unsigned) MemRegion::SymbolicRegionKind);
Ted Kremenek
committed
ID.Add(sym);
Ted Kremenek
committed
ID.AddPointer(sreg);
}
void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const {
Ted Kremenek
committed
SymbolicRegion::ProfileRegion(ID, sym, getSuperRegion());
}
void ElementRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
QualType ElementType, SVal Idx,
const MemRegion* superRegion) {
ID.AddInteger(MemRegion::ElementRegionKind);
ID.Add(ElementType);
ID.AddPointer(superRegion);
Idx.Profile(ID);
}
void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
Zhongxing Xu
committed
void CodeTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const void* data,
QualType t, const MemRegion*) {
ID.AddInteger(MemRegion::CodeTextRegionKind);
ID.AddPointer(data);
ID.Add(t);
}
void CodeTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
CodeTextRegion::ProfileRegion(ID, Data, LocationType, superRegion);
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// Region pretty-printing.
//===----------------------------------------------------------------------===//
void MemRegion::dump() const {
dumpToStream(llvm::errs());
Ted Kremenek
committed
std::string MemRegion::getString() const {
std::string s;
llvm::raw_string_ostream os(s);
dumpToStream(os);
Ted Kremenek
committed
return os.str();
}
void MemRegion::dumpToStream(llvm::raw_ostream& os) const {
Ted Kremenek
committed
os << "<Unknown Region>";
}
void AllocaRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "alloca{" << (void*) Ex << ',' << Cnt << '}';
}
void CodeTextRegion::dumpToStream(llvm::raw_ostream& os) const {
Ted Kremenek
committed
os << "code{";
if (isDeclared())
Ted Kremenek
committed
os << getDecl()->getDeclName().getAsString();
Ted Kremenek
committed
else
os << '$' << getSymbol();
os << '}';
}
void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const {
Ted Kremenek
committed
// FIXME: More elaborate pretty-printing.
os << "{ " << (void*) CL << " }";
Ted Kremenek
committed
}
void ElementRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "element{" << superRegion << ','
<< Index << ',' << getElementType().getAsString() << '}';
}
void FieldRegion::dumpToStream(llvm::raw_ostream& os) const {
os << superRegion << "->" << getDecl()->getNameAsString();
void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "ivar{" << superRegion << ',' << getDecl()->getNameAsString() << '}';
}
void StringRegion::dumpToStream(llvm::raw_ostream& os) const {
Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOptions()));
void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const {
Ted Kremenek
committed
os << "SymRegion{" << sym << '}';
Ted Kremenek
committed
}
void VarRegion::dumpToStream(llvm::raw_ostream& os) const {
Ted Kremenek
committed
os << cast<VarDecl>(D)->getNameAsString();
void RegionRawOffset::dump() const {
dumpToStream(llvm::errs());
}
void RegionRawOffset::dumpToStream(llvm::raw_ostream& os) const {
os << "raw_offset{" << getRegion() << ',' << getByteOffset() << '}';
}
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// MemRegionManager methods.
//===----------------------------------------------------------------------===//
MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) {
Ted Kremenek
committed
if (!region) {
region = (MemSpaceRegion*) A.Allocate<MemSpaceRegion>();
Ted Kremenek
committed
}
Ted Kremenek
committed
return region;
}
MemSpaceRegion* MemRegionManager::getStackRegion() {
return LazyAllocate(stack);
}
Ted Kremenek
committed
MemSpaceRegion* MemRegionManager::getStackArgumentsRegion() {
return LazyAllocate(stackArguments);
}
Ted Kremenek
committed
MemSpaceRegion* MemRegionManager::getGlobalsRegion() {
return LazyAllocate(globals);
}
MemSpaceRegion* MemRegionManager::getHeapRegion() {
return LazyAllocate(heap);
}
MemSpaceRegion* MemRegionManager::getUnknownRegion() {
return LazyAllocate(unknown);
}
MemSpaceRegion* MemRegionManager::getCodeRegion() {
return LazyAllocate(code);
}
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// Constructing regions.
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) {
return getRegion<StringRegion>(Str);
VarRegion* MemRegionManager::getVarRegion(const VarDecl* d) {
Ted Kremenek
committed
return getRegion<VarRegion>(d);
Ted Kremenek
committed
}
Ted Kremenek
committed
CompoundLiteralRegion*
MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) {
Ted Kremenek
committed
return getRegion<CompoundLiteralRegion>(CL);
Ted Kremenek
committed
}
ElementRegion*
MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
const MemRegion* superRegion,
ASTContext& Ctx){
Zhongxing Xu
committed
QualType T = Ctx.getCanonicalType(elementType);
llvm::FoldingSetNodeID ID;
Zhongxing Xu
committed
ElementRegion::ProfileRegion(ID, T, Idx, superRegion);
void* InsertPos;
MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
ElementRegion* R = cast_or_null<ElementRegion>(data);
if (!R) {
R = (ElementRegion*) A.Allocate<ElementRegion>();
Zhongxing Xu
committed
new (R) ElementRegion(T, Idx, superRegion);
Regions.InsertNode(R, InsertPos);
}
return R;
}
CodeTextRegion* MemRegionManager::getCodeTextRegion(const FunctionDecl* fd,
QualType t) {
return getRegion<CodeTextRegion>(fd, t);
}
CodeTextRegion* MemRegionManager::getCodeTextRegion(SymbolRef sym, QualType t) {
return getRegion<CodeTextRegion>(sym, t);
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
Ted Kremenek
committed
SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) {
Ted Kremenek
committed
return getRegion<SymbolicRegion>(sym);
}
Ted Kremenek
committed
FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d,
const MemRegion* superRegion) {
Ted Kremenek
committed
return getSubRegion<FieldRegion>(d, superRegion);
Ted Kremenek
committed
}
ObjCIvarRegion*
MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
const MemRegion* superRegion) {
Ted Kremenek
committed
return getSubRegion<ObjCIvarRegion>(d, superRegion);
Ted Kremenek
committed
}
Ted Kremenek
committed
ObjCObjectRegion*
MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d,
Ted Kremenek
committed
const MemRegion* superRegion) {
Ted Kremenek
committed
return getSubRegion<ObjCObjectRegion>(d, superRegion);
Ted Kremenek
committed
}
AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt) {
Ted Kremenek
committed
return getRegion<AllocaRegion>(E, cnt);
}
const MemSpaceRegion *MemRegion::getMemorySpace() const {
const MemRegion *R = this;
const SubRegion* SR = dyn_cast<SubRegion>(this);
Ted Kremenek
committed
while (SR) {
R = SR->getSuperRegion();
SR = dyn_cast<SubRegion>(R);
Ted Kremenek
committed
}
return dyn_cast<MemSpaceRegion>(R);
Ted Kremenek
committed
}
Ted Kremenek
committed
bool MemRegion::hasStackStorage() const {
Ted Kremenek
committed
if (const MemSpaceRegion *MS = getMemorySpace()) {
MemRegionManager *Mgr = getMemRegionManager();
return MS == Mgr->getStackRegion() || MS == Mgr->getStackArgumentsRegion();
}
bool MemRegion::hasHeapStorage() const {
if (const MemSpaceRegion *MS = getMemorySpace())
return MS == getMemRegionManager()->getHeapRegion();
bool MemRegion::hasHeapOrStackStorage() const {
if (const MemSpaceRegion *MS = getMemorySpace()) {
MemRegionManager *Mgr = getMemRegionManager();
Ted Kremenek
committed
return MS == Mgr->getHeapRegion()
|| MS == Mgr->getStackRegion()
|| MS == Mgr->getStackArgumentsRegion();
Ted Kremenek
committed
}
bool MemRegion::hasGlobalsStorage() const {
if (const MemSpaceRegion *MS = getMemorySpace())
return MS == getMemRegionManager()->getGlobalsRegion();
return false;
}
bool MemRegion::hasParametersStorage() const {
if (const MemSpaceRegion *MS = getMemorySpace())
return MS == getMemRegionManager()->getStackArgumentsRegion();
return false;
}
Ted Kremenek
committed
bool MemRegion::hasGlobalsOrParametersStorage() const {
if (const MemSpaceRegion *MS = getMemorySpace()) {
MemRegionManager *Mgr = getMemRegionManager();
return MS == Mgr->getGlobalsRegion()
|| MS == Mgr->getStackArgumentsRegion();
}
return false;
}
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// View handling.
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
const MemRegion *MemRegion::getBaseRegion() 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) {
Ted Kremenek
committed
R = ER->getSuperRegion();
continue;
}
}
}
break;
}
return R;
}
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
// FIXME: Merge with the implementation of the same method in Store.cpp
static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
const RecordDecl *D = RT->getDecl();
if (!D->getDefinition(Ctx))
return false;
}
return true;
}
RegionRawOffset ElementRegion::getAsRawOffset() const {
int64_t offset = 0;
const ElementRegion *ER = this;
const MemRegion *superR = NULL;
ASTContext &C = getContext();
// FIXME: Handle multi-dimensional arrays.
while (ER) {
superR = ER->getSuperRegion();
// FIXME: generalize to symbolic offsets.
SVal index = ER->getIndex();
if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&index)) {
// Update the offset.
int64_t i = CI->getValue().getSExtValue();
if (i != 0) {
QualType elemType = ER->getElementType();
// If we are pointing to an incomplete type, go no further.
if (!IsCompleteType(C, elemType)) {
superR = ER;
break;
}
int64_t size = (int64_t) (C.getTypeSize(elemType) / 8);
offset += (i * size);
}
// Go to the next ElementRegion (if any).
ER = dyn_cast<ElementRegion>(superR);
continue;
}
return NULL;
}
assert(superR && "super region cannot be NULL");
return RegionRawOffset(superR, offset);
}