Added main logic for typestate tracking for the CFRetain checker.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@48231 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ted Kremenek 2008-03-11 17:48:22 +00:00
Родитель c0a123c81b
Коммит 1ac08d6d92
1 изменённых файлов: 117 добавлений и 11 удалений

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

@ -80,6 +80,11 @@ public:
unsigned getNumArgs() const { return Args->size(); }
ArgEffect getArg(unsigned idx) const {
assert (idx < getNumArgs());
return (*Args)[idx];
}
typedef ArgEffects::const_iterator arg_iterator;
arg_iterator begin_args() const { return Args->begin(); }
@ -152,12 +157,45 @@ CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD) {
// Transfer functions.
//===----------------------------------------------------------------------===//
typedef unsigned RefState; // FIXME
namespace {
class RefVal {
unsigned Data;
RefVal(unsigned K, unsigned D) : Data((D << 3) | K) {
assert ((K & ~0x5) == 0x0);
}
RefVal(unsigned K) : Data(K) {
assert ((K & ~0x5) == 0x0);
}
public:
enum Kind { Owned = 0, AcqOwned = 1, NotOwned = 2, Released = 3,
ErrorUseAfterRelease = 4, ErrorReleaseNotOwned = 5 };
Kind getKind() const { return (Kind) (Data & 0x5); }
unsigned getCount() const {
assert (getKind() == Owned || getKind() == AcqOwned);
return Data >> 3;
}
static RefVal makeOwned(unsigned Count) { return RefVal(Owned, Count); }
static RefVal makeAcqOwned(unsigned Count) { return RefVal(AcqOwned, Count); }
static RefVal makeNotOwned() { return RefVal(NotOwned); }
static RefVal makeReleased() { return RefVal(Released); }
static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); }
static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); }
bool operator==(const RefVal& X) const { return Data == X.Data; }
void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
};
class CFRefCount : public GRSimpleVals {
typedef llvm::ImmutableMap<SymbolID, RefState> RefBindings;
typedef llvm::ImmutableMap<SymbolID, RefVal> RefBindings;
typedef RefBindings::Factory RefBFactoryTy;
CFRefSummaryManager Summaries;
@ -175,8 +213,8 @@ class CFRefCount : public GRSimpleVals {
return RefBFactory.Remove(B, sym);
}
RefBindings Update(RefBindings B, SymbolID sym,
CFRefSummary* Summ, unsigned ArgIdx);
RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
bool& hasError);
public:
CFRefCount() {}
@ -220,6 +258,7 @@ void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
// Evaluate the effects of the call.
ValueState StVals = *St;
bool hasError = false;
if (!Summ) {
@ -258,25 +297,92 @@ void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
if (isa<lval::SymbolVal>(V)) {
SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
RefBindings B = GetRefBindings(StVals);
SetRefBindings(StVals, Update(B, Sym, Summ, idx));
if (RefBindings::TreeTy* T = B.SlimFind(Sym)) {
B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError);
SetRefBindings(StVals, B);
if (hasError) break;
}
}
}
}
St = StateMgr.getPersistentState(StVals);
if (hasError) {
}
Builder.Nodify(Dst, CE, Pred, St);
}
CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
CFRefSummary* Summ, unsigned ArgIdx){
RefVal V, ArgEffect E,
bool& hasError) {
assert (Summ);
// FIXME: This dispatch can potentially be sped up by unifiying it into
// a single switch statement. Opt for simplicity for now.
// FIXME: Implement.
return B;
switch (E) {
default:
assert (false && "Unhandled CFRef transition.");
case DoNothing:
return B;
case IncRef:
switch (V.getKind()) {
default:
assert(false);
case RefVal::Owned:
V = RefVal::makeOwned(V.getCount()+1); break;
case RefVal::AcqOwned:
V = RefVal::makeAcqOwned(V.getCount()+1);
break;
case RefVal::NotOwned:
V = RefVal::makeAcqOwned(1);
break;
case RefVal::Released:
hasError = true;
V = RefVal::makeUseAfterRelease();
break;
}
case DecRef:
switch (V.getKind()) {
default:
assert (false);
case RefVal::Owned: {
unsigned Count = V.getCount() - 1;
V = Count ? RefVal::makeOwned(Count) : RefVal::makeReleased();
break;
}
case RefVal::AcqOwned: {
unsigned Count = V.getCount() - 1;
V = Count ? RefVal::makeAcqOwned(Count) : RefVal::makeNotOwned();
break;
}
case RefVal::NotOwned:
hasError = true;
V = RefVal::makeReleaseNotOwned();
break;
case RefVal::Released:
hasError = true;
V = RefVal::makeUseAfterRelease();
break;
}
}
return RefBFactory.Add(B, sym, V);
}
//===----------------------------------------------------------------------===//