Added support for "autorelease" message in CF ref. count checker.

llvm-svn: 50512
This commit is contained in:
Ted Kremenek 2008-05-01 02:18:37 +00:00
parent 20348b5653
commit 4828aa3152
1 changed files with 42 additions and 15 deletions

View File

@ -637,6 +637,7 @@ private:
Selector RetainSelector;
Selector ReleaseSelector;
Selector AutoreleaseSelector;
public:
@ -677,7 +678,8 @@ public:
GCEnabled(gcenabled),
LOpts(lopts),
RetainSelector(GetUnarySelector("retain", Ctx)),
ReleaseSelector(GetUnarySelector("release", Ctx)) {}
ReleaseSelector(GetUnarySelector("release", Ctx)),
AutoreleaseSelector(GetUnarySelector("autorelease", Ctx)) {}
virtual ~CFRefCount() {
for (LeaksTy::iterator I = Leaks.begin(), E = Leaks.end(); I!=E; ++I)
@ -989,43 +991,68 @@ bool CFRefCount::EvalObjCMessageExprAux(ExplodedNodeSet<ValueState>& Dst,
if (!Receiver)
return true;
// Check if we are calling "Retain" or "Release".
// Check if we are calling "autorelease".
enum { IsRelease, IsRetain, IsAutorelease, IsNone } mode = IsNone;
bool isRetain = false;
if (S == AutoreleaseSelector)
mode = IsAutorelease;
else if (S == RetainSelector)
mode = IsRetain;
else if (S == ReleaseSelector)
mode = IsRelease;
if (S == RetainSelector)
isRetain = true;
else if (S != ReleaseSelector)
if (mode == IsNone)
return true;
// We have "Retain" or "Release". Get the reference binding.
// We have "retain", "release", or "autorelease".
ValueStateManager& StateMgr = Eng.getStateManager();
ValueState* St = Builder.GetState(Pred);
RVal V = StateMgr.GetRVal(St, Receiver);
// Was the argument something we are not tracking?
if (!isa<lval::SymbolVal>(V))
return true;
// Get the bindings.
SymbolID Sym = cast<lval::SymbolVal>(V).getSymbol();
RefBindings B = GetRefBindings(*St);
// Find the tracked value.
RefBindings::TreeTy* T = B.SlimFind(Sym);
if (!T)
return true;
RefVal::Kind hasErr = (RefVal::Kind) 0;
B = Update(B, Sym, T->getValue().second, isRetain ? IncRef : DecRef, hasErr);
// Create a new state with the updated bindings.
RefVal::Kind hasErr = (RefVal::Kind) 0;
// Update the bindings.
switch (mode) {
case IsNone:
assert(false);
case IsRelease:
B = Update(B, Sym, T->getValue().second, DecRef, hasErr);
break;
case IsRetain:
B = Update(B, Sym, T->getValue().second, IncRef, hasErr);
break;
case IsAutorelease:
// For now we just stop tracking a value if we see
// it sent "autorelease." In the future we can potentially
// track the associated pool.
B = Remove(B, Sym);
break;
}
// Create a new state with the updated bindings.
ValueState StVals = *St;
SetRefBindings(StVals, B);
St = StateMgr.getPersistentState(StVals);
// Create an error node if it exists.
// Create an error node if it exists.
if (hasErr)
ProcessNonLeakError(Dst, Builder, ME, Receiver, Pred, St, hasErr, Sym);
else