Rework use of loc::SymbolVal in the retain/release checker to use the new method

SVal::getAsLocSymbol(). This simplifies the code and allows the retain/release
checker to (I believe) also correctly reason about location symbols wrapped in
SymbolicRegions.

Along the way I cleaned up SymbolRef a little, disallowing implicit casts to
'unsigned'.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65972 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ted Kremenek 2009-03-03 22:06:47 +00:00
Родитель 9d40ee50f8
Коммит 94c969804b
7 изменённых файлов: 140 добавлений и 103 удалений

Просмотреть файл

@ -66,8 +66,7 @@ public:
inline bool operator==(const SVal& R) const {
return getRawKind() == R.getRawKind() && Data == R.Data;
}
inline bool operator!=(const SVal& R) const {
return !(*this == R);
}
@ -75,7 +74,6 @@ public:
/// GetRValueSymbolVal - make a unique symbol for value of R.
static SVal GetRValueSymbolVal(SymbolManager& SymMgr, const MemRegion* R);
inline bool isUnknown() const {
return getRawKind() == UnknownKind;
}
@ -94,6 +92,15 @@ public:
bool isZeroConstant() const;
/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
/// wraps a symbol, return that SymbolRef. Otherwise return a SymbolRef
/// where 'isValid()' returns false.
SymbolRef getAsLocSymbol() const;
/// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
/// Otherwise return a SymbolRef where 'isValid()' returns false.
SymbolRef getAsSymbol() const;
void print(std::ostream& OS) const;
void print(llvm::raw_ostream& OS) const;
void printStdErr() const;
@ -237,8 +244,9 @@ enum Kind { ConcreteIntKind, SymbolValKind, SymIntConstraintValKind,
class SymbolVal : public NonLoc {
public:
SymbolVal(unsigned SymID)
: NonLoc(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID)) {}
SymbolVal(SymbolRef SymID)
: NonLoc(SymbolValKind,
reinterpret_cast<void*>((uintptr_t) SymID.getNumber())) {}
SymbolRef getSymbol() const {
return (SymbolRef) reinterpret_cast<uintptr_t>(Data);
@ -370,8 +378,8 @@ enum Kind { SymbolValKind, GotoLabelKind, MemRegionKind, FuncValKind,
class SymbolVal : public Loc {
public:
SymbolVal(unsigned SymID)
: Loc(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID)) {}
SymbolVal(SymbolRef SymID)
: Loc(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID.getNumber())){}
SymbolRef getSymbol() const {
return (SymbolRef) reinterpret_cast<uintptr_t>(Data);

Просмотреть файл

@ -39,40 +39,45 @@ class SymbolRef {
public:
SymbolRef() : Data(~0U - 2) {}
SymbolRef(unsigned x) : Data(x) {}
bool isInitialized() const { return Data != (unsigned) (~0U - 2); }
operator unsigned() const { return getNumber(); }
unsigned getNumber() const { assert (isInitialized()); return Data; }
bool isValid() const { return Data != (unsigned) (~0U - 2); }
unsigned getNumber() const { assert (isValid()); return Data; }
bool operator<(const SymbolRef& X) const { return Data < X.Data; }
bool operator>(const SymbolRef& X) const { return Data > X.Data; }
bool operator==(const SymbolRef& X) const { return Data == X.Data; }
bool operator!=(const SymbolRef& X) const { return Data != X.Data; }
void print(llvm::raw_ostream& os) const;
void Profile(llvm::FoldingSetNodeID& ID) const {
assert (isInitialized());
assert (isValid());
ID.AddInteger(Data);
}
};
} // end clang namespace
namespace llvm {
template <> struct DenseMapInfo<clang::SymbolRef> {
static inline clang::SymbolRef getEmptyKey() {
return clang::SymbolRef(~0U);
}
static inline clang::SymbolRef getTombstoneKey() {
return clang::SymbolRef(~0U - 1);
}
static unsigned getHashValue(clang::SymbolRef X) {
return X.getNumber();
}
static bool isEqual(clang::SymbolRef X, clang::SymbolRef Y) {
return X.getNumber() == Y.getNumber();
}
static bool isPod() { return true; }
};
llvm::raw_ostream& operator<<(llvm::raw_ostream& Out, clang::SymbolRef Sym);
}
namespace std {
std::ostream& operator<<(std::ostream& Out, clang::SymbolRef Sym);
}
namespace llvm {
template <> struct DenseMapInfo<clang::SymbolRef> {
static inline clang::SymbolRef getEmptyKey() {
return clang::SymbolRef(~0U);
}
static inline clang::SymbolRef getTombstoneKey() {
return clang::SymbolRef(~0U - 1);
}
static unsigned getHashValue(clang::SymbolRef X) {
return X.getNumber();
}
static bool isEqual(clang::SymbolRef X, clang::SymbolRef Y) {
return X == Y;
}
static bool isPod() { return true; }
};
}
// SymbolData: Used to record meta data about symbols.

Просмотреть файл

@ -531,7 +531,7 @@ public:
else
return true;
assert (ScanSym.isInitialized());
assert (ScanSym.isValid());
if (!BR.isNotable(ScanSym))
return true;

Просмотреть файл

@ -1613,20 +1613,20 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) {
SVal V = state.GetSVal(*I);
if (isa<loc::SymbolVal>(V)) {
SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
SymbolRef Sym = V.getAsLocSymbol();
if (Sym.isValid())
if (RefBindings::data_type* T = state.get<RefBindings>(Sym)) {
state = Update(state, Sym, *T, GetArgE(Summ, idx), hasErr);
if (hasErr) {
ErrorExpr = *I;
ErrorSym = Sym;
break;
}
}
continue;
}
}
else if (isa<Loc>(V)) {
if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) {
if (isa<Loc>(V)) {
if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) {
if (GetArgE(Summ, idx) == DoNothingByRef)
continue;
@ -1650,15 +1650,11 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
R = dyn_cast<TypedRegion>(ATR->getSuperRegion());
}
if (R) {
if (R) {
// Is the invalidated variable something that we were tracking?
SVal X = state.GetSVal(Loc::MakeVal(R));
if (isa<loc::SymbolVal>(X)) {
SymbolRef Sym = cast<loc::SymbolVal>(X).getSymbol();
SymbolRef Sym = state.GetSVal(Loc::MakeVal(R)).getAsLocSymbol();
if (Sym.isValid())
state = state.remove<RefBindings>(Sym);
}
// Set the value of the variable to be a conjured symbol.
unsigned Count = Builder.getCurrentBlockCount();
@ -1692,9 +1688,8 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
// Evaluate the effect on the message receiver.
if (!ErrorExpr && Receiver) {
SVal V = state.GetSVal(Receiver);
if (isa<loc::SymbolVal>(V)) {
SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
SymbolRef Sym = state.GetSVal(Receiver).getAsLocSymbol();
if (Sym.isValid()) {
if (const RefVal* T = state.get<RefBindings>(Sym)) {
state = Update(state, Sym, *T, GetReceiverE(Summ), hasErr);
if (hasErr) {
@ -1831,11 +1826,10 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
// FIXME: Wouldn't it be great if this code could be reduced? It's just
// a chain of lookups.
const GRState* St = Builder.GetState(Pred);
SVal V = Eng.getStateManager().GetSVal(St, Receiver );
SVal V = Eng.getStateManager().GetSVal(St, Receiver);
if (isa<loc::SymbolVal>(V)) {
SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
SymbolRef Sym = V.getAsLocSymbol();
if (Sym.isValid()) {
if (const RefVal* T = St->get<RefBindings>(Sym)) {
QualType Ty = T->getType();
@ -1979,16 +1973,16 @@ void CFRefCount::EvalReturn(ExplodedNodeSet<GRState>& Dst,
ExplodedNode<GRState>* Pred) {
Expr* RetE = S->getRetValue();
if (!RetE) return;
GRStateRef state(Builder.GetState(Pred), Eng.getStateManager());
SVal V = state.GetSVal(RetE);
if (!isa<loc::SymbolVal>(V))
if (!RetE)
return;
GRStateRef state(Builder.GetState(Pred), Eng.getStateManager());
SymbolRef Sym = state.GetSVal(RetE).getAsLocSymbol();
if (!Sym.isValid())
return;
// Get the reference count binding (if any).
SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
const RefVal* T = state.get<RefBindings>(Sym);
if (!T)
@ -2461,27 +2455,21 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode<GRState>* N,
for (CallExpr::arg_iterator AI=CE->arg_begin(), AE=CE->arg_end();
AI!=AE; ++AI, ++i) {
// Retrieve the value of the arugment.
SVal X = CurrSt.GetSVal(*AI);
// Is it the symbol we're interested in?
if (!isa<loc::SymbolVal>(X) ||
Sym != cast<loc::SymbolVal>(X).getSymbol())
// Retrieve the value of the argument. Is it the symbol
// we are interested in?
if (CurrSt.GetSVal(*AI).getAsLocSymbol() != Sym)
continue;
// We have an argument. Get the effect!
AEffects.push_back(Summ->getArg(i));
}
}
else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
if (Expr *receiver = ME->getReceiver()) {
SVal RetV = CurrSt.GetSVal(receiver);
if (isa<loc::SymbolVal>(RetV) &&
Sym == cast<loc::SymbolVal>(RetV).getSymbol()) {
if (Expr *receiver = ME->getReceiver())
if (CurrSt.GetSVal(receiver).getAsLocSymbol() == Sym) {
// The symbol we are tracking is the receiver.
AEffects.push_back(Summ->getReceiverEffect());
}
}
}
}
@ -2596,14 +2584,11 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode<GRState>* N,
// Add the range by scanning the children of the statement for any bindings
// to Sym.
for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
if (Expr* Exp = dyn_cast_or_null<Expr>(*I)) {
SVal X = CurrSt.GetSVal(Exp);
if (loc::SymbolVal* SV = dyn_cast<loc::SymbolVal>(&X))
if (SV->getSymbol() == Sym) {
P->addRange(Exp->getSourceRange());
break;
}
}
if (Expr* Exp = dyn_cast_or_null<Expr>(*I))
if (CurrSt.GetSVal(Exp).getAsLocSymbol() == Sym) {
P->addRange(Exp->getSourceRange());
break;
}
return P;
}
@ -2619,17 +2604,11 @@ class VISIBILITY_HIDDEN FindUniqueBinding :
FindUniqueBinding(SymbolRef sym) : Sym(sym), Binding(0), First(true) {}
bool HandleBinding(StoreManager& SMgr, Store store, MemRegion* R, SVal val) {
if (const loc::SymbolVal* SV = dyn_cast<loc::SymbolVal>(&val)) {
if (SV->getSymbol() != Sym)
return true;
}
else if (const nonloc::SymbolVal* SV=dyn_cast<nonloc::SymbolVal>(&val)) {
if (SV->getSymbol() != Sym)
return true;
}
else
SymbolRef SymV = val.getAsSymbol();
if (!SymV.isValid() || SymV != Sym)
return true;
if (Binding) {
First = false;
return false;
@ -2731,20 +2710,16 @@ CFRefLeakReport::getEndPath(BugReporter& br, const ExplodedNode<GRState>* EndN){
bool foundSymbol = false;
// First check if 'S' itself binds to the symbol.
if (Expr *Ex = dyn_cast<Expr>(S)) {
SVal X = state.GetSVal(Ex);
if (isa<loc::SymbolVal>(X) &&
cast<loc::SymbolVal>(X).getSymbol() == Sym)
if (Expr *Ex = dyn_cast<Expr>(S))
if (state.GetSVal(Ex).getAsLocSymbol() == Sym)
foundSymbol = true;
}
if (!foundSymbol)
for (Stmt::child_iterator I=S->child_begin(), E=S->child_end();
I!=E; ++I)
if (Expr *Ex = dyn_cast_or_null<Expr>(*I)) {
SVal X = state.GetSVal(Ex);
if (isa<loc::SymbolVal>(X) &&
cast<loc::SymbolVal>(X).getSymbol() == Sym){
if (X.getAsLocSymbol() == Sym) {
foundSymbol = true;
break;
}
@ -2848,8 +2823,8 @@ void CFRefCount::EvalEndPath(GRExprEngine& Eng,
bool hasLeak = false;
std::pair<GRStateRef, bool> X =
HandleSymbolDeath(Eng.getStateManager(), St, CodeDecl,
(*I).first, (*I).second, hasLeak);
HandleSymbolDeath(Eng.getStateManager(), St, CodeDecl,
(*I).first, (*I).second, hasLeak);
St = X.first;
if (hasLeak) Leaked.push_back(std::make_pair((*I).first, X.second));

Просмотреть файл

@ -171,8 +171,7 @@ void VarRegion::print(llvm::raw_ostream& os) const {
}
void SymbolicRegion::print(llvm::raw_ostream& os) const {
os << "SymRegion-";
sym.print(os);
os << "SymRegion-" << sym;
}
void FieldRegion::print(llvm::raw_ostream& os) const {

Просмотреть файл

@ -54,6 +54,42 @@ SVal::symbol_iterator SVal::symbol_end() const {
return symbol_iterator();
}
/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
/// wraps a symbol, return that SymbolRef. Otherwise return a SymbolRef
/// where 'isValid()' returns false.
SymbolRef SVal::getAsLocSymbol() const {
if (const loc::SymbolVal *X = dyn_cast<loc::SymbolVal>(this))
return X->getSymbol();
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) {
const MemRegion *R = X->getRegion();
while (R) {
// Blast through region views.
if (const TypedViewRegion *View = dyn_cast<TypedViewRegion>(R)) {
R = View->getSuperRegion();
continue;
}
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
return SymR->getSymbol();
break;
}
}
return SymbolRef();
}
/// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
/// Otherwise return a SymbolRef where 'isValid()' returns false.
SymbolRef SVal::getAsSymbol() const {
if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
return X->getSymbol();
return getAsLocSymbol();
}
//===----------------------------------------------------------------------===//
// Other Iterators.
//===----------------------------------------------------------------------===//

Просмотреть файл

@ -18,8 +18,23 @@
using namespace clang;
void SymbolRef::print(llvm::raw_ostream& os) const {
os << getNumber();
llvm::raw_ostream& llvm::operator<<(llvm::raw_ostream& os,
clang::SymbolRef sym) {
if (sym.isValid())
os << sym.getNumber();
else
os << "(Invalid)";
return os;
}
std::ostream& std::operator<<(std::ostream& os, clang::SymbolRef sym) {
if (sym.isValid())
os << sym.getNumber();
else
os << "(Invalid)";
return os;
}
SymbolRef SymbolManager::getRegionRValueSymbol(const MemRegion* R) {
@ -35,7 +50,6 @@ SymbolRef SymbolManager::getRegionRValueSymbol(const MemRegion* R) {
DataSet.InsertNode(SD, InsertPos);
DataMap[SymbolCounter] = SD;
return SymbolCounter++;
}
SymbolRef SymbolManager::getConjuredSymbol(Stmt* E, QualType T, unsigned Count){