Initial work on refactoring the CFRefCount checker so that it is more

generic and handles reference counts for NSObjects.

llvm-svn: 50674
This commit is contained in:
Ted Kremenek 2008-05-05 22:11:16 +00:00
parent 4ead264c08
commit 00daccdd2a
1 changed files with 184 additions and 108 deletions

View File

@ -63,23 +63,25 @@ namespace {
class RetEffect { class RetEffect {
public: public:
enum Kind { NoRet = 0x0, Alias = 0x1, OwnedSymbol = 0x2, enum Kind { NoRet = 0x0, Alias = 0x1, OwnedSymbol = 0x2,
NotOwnedSymbol = 0x3 }; NotOwnedSymbol = 0x3, ReceiverAlias=0x4 };
private: private:
unsigned Data; unsigned Data;
RetEffect(Kind k, unsigned D) { Data = (D << 2) | (unsigned) k; } RetEffect(Kind k, unsigned D) { Data = (D << 3) | (unsigned) k; }
public: public:
Kind getKind() const { return (Kind) (Data & 0x3); } Kind getKind() const { return (Kind) (Data & 0x7); }
unsigned getValue() const { unsigned getValue() const {
assert(getKind() == Alias); assert(getKind() == Alias);
return Data >> 2; return Data >> 3;
} }
static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); } static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
static RetEffect MakeReceiverAlias() { return RetEffect(ReceiverAlias, 0); }
static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); } static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); } static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
@ -92,12 +94,12 @@ public:
}; };
class CFRefSummary : public llvm::FoldingSetNode { class RetainSummary : public llvm::FoldingSetNode {
ArgEffects* Args; ArgEffects* Args;
RetEffect Ret; RetEffect Ret;
public: public:
CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {} RetainSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
unsigned getNumArgs() const { return Args->size(); } unsigned getNumArgs() const { return Args->size(); }
@ -143,40 +145,86 @@ public:
}; };
class CFRefSummaryManager { class RetainSummaryManager {
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
typedef llvm::FoldingSet<CFRefSummary> SummarySetTy; //==-----------------------------------------------------------------==//
typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*> SummaryMapTy; // Typedefs.
//==-----------------------------------------------------------------==//
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> >
ArgEffectsSetTy;
typedef llvm::FoldingSet<RetainSummary>
SummarySetTy;
typedef llvm::DenseMap<FunctionDecl*, RetainSummary*>
FuncSummariesTy;
typedef llvm::DenseMap<Selector, RetainSummary*>
ObjCMethodSummariesTy;
//==-----------------------------------------------------------------==//
// Data.
//==-----------------------------------------------------------------==//
// Ctx - The ASTContext object for the analyzed ASTs.
ASTContext& Ctx; ASTContext& Ctx;
// GCEnabled - Records whether or not the analyzed code runs in GC mode.
const bool GCEnabled; const bool GCEnabled;
// SummarySet - A FoldingSet of uniqued summaries.
SummarySetTy SummarySet; SummarySetTy SummarySet;
SummaryMapTy SummaryMap;
AESetTy AESet;
llvm::BumpPtrAllocator BPAlloc;
ArgEffects ScratchArgs;
// FuncSummaries - A map from FunctionDecls to summaries.
FuncSummariesTy FuncSummaries;
// ObjCInstanceMethodSummaries - A map from selectors (for instance methods)
// to summaries.
ObjCMethodSummariesTy ObjCInstanceMethodSummaries;
// ObjCMethodSummaries - A map from selectors to summaries.
ObjCMethodSummariesTy ObjCMethodSummaries;
// ArgEffectsSet - A FoldingSet of uniqued ArgEffects.
ArgEffectsSetTy ArgEffectsSet;
// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects,
// and all other data used by the checker.
llvm::BumpPtrAllocator BPAlloc;
// ScratchArgs - A holding buffer for construct ArgEffects.
ArgEffects ScratchArgs;
//==-----------------------------------------------------------------==//
// Methods.
//==-----------------------------------------------------------------==//
// getArgEffects - Returns a persistent ArgEffects object based on the
// data in ScratchArgs.
ArgEffects* getArgEffects(); ArgEffects* getArgEffects();
enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable }; enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable };
CFRefSummary* getUnarySummary(FunctionDecl* FD, UnaryFuncKind func); RetainSummary* getUnarySummary(FunctionDecl* FD, UnaryFuncKind func);
CFRefSummary* getNSSummary(FunctionDecl* FD, const char* FName); RetainSummary* getNSSummary(FunctionDecl* FD, const char* FName);
CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName); RetainSummary* getCFSummary(FunctionDecl* FD, const char* FName);
CFRefSummary* getCFSummaryCreateRule(FunctionDecl* FD); RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD);
CFRefSummary* getCFSummaryGetRule(FunctionDecl* FD); RetainSummary* getCFSummaryGetRule(FunctionDecl* FD);
CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE); RetainSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
public: public:
CFRefSummaryManager(ASTContext& ctx, bool gcenabled)
RetainSummaryManager(ASTContext& ctx, bool gcenabled)
: Ctx(ctx), GCEnabled(gcenabled) {} : Ctx(ctx), GCEnabled(gcenabled) {}
~CFRefSummaryManager(); ~RetainSummaryManager();
CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx); RetainSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
bool isGCEnabled() const { return GCEnabled; }
}; };
} // end anonymous namespace } // end anonymous namespace
@ -185,17 +233,17 @@ public:
// Implementation of checker data structures. // Implementation of checker data structures.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
CFRefSummaryManager::~CFRefSummaryManager() { RetainSummaryManager::~RetainSummaryManager() {
// FIXME: The ArgEffects could eventually be allocated from BPAlloc, // FIXME: The ArgEffects could eventually be allocated from BPAlloc,
// mitigating the need to do explicit cleanup of the // mitigating the need to do explicit cleanup of the
// Argument-Effect summaries. // Argument-Effect summaries.
for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I) for (ArgEffectsSetTy::iterator I = ArgEffectsSet.begin(), E = ArgEffectsSet.end(); I!=E; ++I)
I->getValue().~ArgEffects(); I->getValue().~ArgEffects();
} }
ArgEffects* CFRefSummaryManager::getArgEffects() { ArgEffects* RetainSummaryManager::getArgEffects() {
if (ScratchArgs.empty()) if (ScratchArgs.empty())
return NULL; return NULL;
@ -210,7 +258,7 @@ ArgEffects* CFRefSummaryManager::getArgEffects() {
// Look up the uniqued copy, or create a new one. // Look up the uniqued copy, or create a new one.
llvm::FoldingSetNodeWrapper<ArgEffects>* E = llvm::FoldingSetNodeWrapper<ArgEffects>* E =
AESet.FindNodeOrInsertPos(profile, InsertPos); ArgEffectsSet.FindNodeOrInsertPos(profile, InsertPos);
if (E) { if (E) {
ScratchArgs.clear(); ScratchArgs.clear();
@ -221,36 +269,39 @@ ArgEffects* CFRefSummaryManager::getArgEffects() {
BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >(); BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs); new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
AESet.InsertNode(E, InsertPos); ArgEffectsSet.InsertNode(E, InsertPos);
ScratchArgs.clear(); ScratchArgs.clear();
return &E->getValue(); return &E->getValue();
} }
CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE, RetainSummary* RetainSummaryManager::getPersistentSummary(ArgEffects* AE,
RetEffect RE) { RetEffect RE) {
// Generate a profile for the summary. // Generate a profile for the summary.
llvm::FoldingSetNodeID profile; llvm::FoldingSetNodeID profile;
CFRefSummary::Profile(profile, AE, RE); RetainSummary::Profile(profile, AE, RE);
// Look up the uniqued summary, or create one if it doesn't exist. // Look up the uniqued summary, or create one if it doesn't exist.
void* InsertPos; void* InsertPos;
CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos); RetainSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
if (Summ) if (Summ)
return Summ; return Summ;
// Create the summary and return it. // Create the summary and return it.
Summ = (CFRefSummary*) BPAlloc.Allocate<CFRefSummary>(); Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
new (Summ) CFRefSummary(AE, RE); new (Summ) RetainSummary(AE, RE);
SummarySet.InsertNode(Summ, InsertPos); SummarySet.InsertNode(Summ, InsertPos);
return Summ; return Summ;
} }
//===----------------------------------------------------------------------===//
// Summary creation for functions (largely uses of Core Foundation).
//===----------------------------------------------------------------------===//
CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD, RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD,
ASTContext& Ctx) { ASTContext& Ctx) {
SourceLocation Loc = FD->getLocation(); SourceLocation Loc = FD->getLocation();
@ -259,26 +310,26 @@ CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD,
return NULL; return NULL;
// Look up a summary in our cache of FunctionDecls -> Summaries. // Look up a summary in our cache of FunctionDecls -> Summaries.
SummaryMapTy::iterator I = SummaryMap.find(FD); FuncSummariesTy::iterator I = FuncSummaries.find(FD);
if (I != SummaryMap.end()) if (I != FuncSummaries.end())
return I->second; return I->second;
// No summary. Generate one. // No summary. Generate one.
const char* FName = FD->getIdentifier()->getName(); const char* FName = FD->getIdentifier()->getName();
CFRefSummary *S = 0; RetainSummary *S = 0;
if (FName[0] == 'C' && FName[1] == 'F') if (FName[0] == 'C' && FName[1] == 'F')
S = getCFSummary(FD, FName); S = getCFSummary(FD, FName);
else if (FName[0] == 'N' && FName[1] == 'S') else if (FName[0] == 'N' && FName[1] == 'S')
S = getNSSummary(FD, FName); S = getNSSummary(FD, FName);
SummaryMap[FD] = S; FuncSummaries[FD] = S;
return S; return S;
} }
CFRefSummary* CFRefSummaryManager::getNSSummary(FunctionDecl* FD, RetainSummary* RetainSummaryManager::getNSSummary(FunctionDecl* FD,
const char* FName) { const char* FName) {
FName += 2; FName += 2;
@ -288,7 +339,7 @@ CFRefSummary* CFRefSummaryManager::getNSSummary(FunctionDecl* FD,
return 0; return 0;
} }
CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD, RetainSummary* RetainSummaryManager::getCFSummary(FunctionDecl* FD,
const char* FName) { const char* FName) {
FName += 2; FName += 2;
@ -311,8 +362,8 @@ CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD,
return 0; return 0;
} }
CFRefSummary* RetainSummary*
CFRefSummaryManager::getUnarySummary(FunctionDecl* FD, UnaryFuncKind func) { RetainSummaryManager::getUnarySummary(FunctionDecl* FD, UnaryFuncKind func) {
FunctionTypeProto* FT = FunctionTypeProto* FT =
dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr()); dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
@ -330,7 +381,7 @@ CFRefSummaryManager::getUnarySummary(FunctionDecl* FD, UnaryFuncKind func) {
if (!ArgT->isPointerType()) if (!ArgT->isPointerType())
return NULL; return NULL;
} }
assert (ScratchArgs.empty()); assert (ScratchArgs.empty());
switch (func) { switch (func) {
@ -380,8 +431,7 @@ static bool isCFRefType(QualType T) {
return true; return true;
} }
CFRefSummary* RetainSummary* RetainSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) {
CFRefSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) {
FunctionTypeProto* FT = FunctionTypeProto* FT =
dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr()); dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
@ -396,8 +446,7 @@ CFRefSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) {
return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned()); return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
} }
CFRefSummary* RetainSummary* RetainSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) {
CFRefSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) {
FunctionTypeProto* FT = FunctionTypeProto* FT =
dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr()); dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
@ -422,6 +471,13 @@ CFRefSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) {
return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned()); return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned());
} }
//===----------------------------------------------------------------------===//
// Summary creation for Selectors.
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Reference-counting logic (typestate + counts). // Reference-counting logic (typestate + counts).
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -610,11 +666,10 @@ public:
private: private:
// Instance variables. // Instance variables.
CFRefSummaryManager Summaries; RetainSummaryManager Summaries;
const bool GCEnabled; const bool EmitStandardWarnings;
const bool EmitStandardWarnings; const LangOptions& LOpts;
const LangOptions& LOpts; RefBFactoryTy RefBFactory;
RefBFactoryTy RefBFactory;
UseAfterReleasesTy UseAfterReleases; UseAfterReleasesTy UseAfterReleases;
ReleasesNotOwnedTy ReleasesNotOwned; ReleasesNotOwnedTy ReleasesNotOwned;
@ -663,7 +718,6 @@ public:
CFRefCount(ASTContext& Ctx, bool gcenabled, bool StandardWarnings, CFRefCount(ASTContext& Ctx, bool gcenabled, bool StandardWarnings,
const LangOptions& lopts) const LangOptions& lopts)
: Summaries(Ctx, gcenabled), : Summaries(Ctx, gcenabled),
GCEnabled(gcenabled),
EmitStandardWarnings(StandardWarnings), EmitStandardWarnings(StandardWarnings),
LOpts(lopts), LOpts(lopts),
RetainSelector(GetNullarySelector("retain", Ctx)), RetainSelector(GetNullarySelector("retain", Ctx)),
@ -681,17 +735,27 @@ public:
return &Printer; return &Printer;
} }
bool isGCEnabled() const { return GCEnabled; } bool isGCEnabled() const { return Summaries.isGCEnabled(); }
const LangOptions& getLangOptions() const { return LOpts; } const LangOptions& getLangOptions() const { return LOpts; }
// Calls. // Calls.
void EvalSummary(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder,
Expr* Ex,
Expr* Receiver,
RetainSummary* Summ,
Expr** arg_beg, Expr** arg_end,
ExplodedNode<ValueState>* Pred);
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst, virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Eng, GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder, GRStmtNodeBuilder<ValueState>& Builder,
CallExpr* CE, RVal L, CallExpr* CE, RVal L,
ExplodedNode<ValueState>* Pred); ExplodedNode<ValueState>* Pred);
virtual void EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst, virtual void EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Engine, GRExprEngine& Engine,
GRStmtNodeBuilder<ValueState>& Builder, GRStmtNodeBuilder<ValueState>& Builder,
@ -772,11 +836,11 @@ void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out,
} }
} }
static inline ArgEffect GetArgE(CFRefSummary* Summ, unsigned idx) { static inline ArgEffect GetArgE(RetainSummary* Summ, unsigned idx) {
return Summ ? Summ->getArg(idx) : DoNothing; return Summ ? Summ->getArg(idx) : DoNothing;
} }
static inline RetEffect GetRetE(CFRefSummary* Summ) { static inline RetEffect GetRetE(RetainSummary* Summ) {
return Summ ? Summ->getRet() : RetEffect::MakeNoRet(); return Summ ? Summ->getRet() : RetEffect::MakeNoRet();
} }
@ -803,33 +867,25 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet<ValueState>& Dst,
} }
} }
void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst, void CFRefCount::EvalSummary(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Eng, GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder, GRStmtNodeBuilder<ValueState>& Builder,
CallExpr* CE, RVal L, Expr* Ex,
ExplodedNode<ValueState>* Pred) { Expr* Receiver,
RetainSummary* Summ,
Expr** arg_beg, Expr** arg_end,
ExplodedNode<ValueState>* Pred) {
ValueStateManager& StateMgr = Eng.getStateManager();
CFRefSummary* Summ = NULL;
// Get the summary.
if (isa<lval::FuncVal>(L)) {
lval::FuncVal FV = cast<lval::FuncVal>(L);
FunctionDecl* FD = FV.getDecl();
Summ = Summaries.getSummary(FD, Eng.getContext());
}
// Get the state. // Get the state.
ValueStateManager& StateMgr = Eng.getStateManager();
ValueState* St = Builder.GetState(Pred); ValueState* St = Builder.GetState(Pred);
// Evaluate the effects of the call. // Evaluate the effects of the call.
ValueState StVals = *St; ValueState StVals = *St;
RefVal::Kind hasErr = (RefVal::Kind) 0; RefVal::Kind hasErr = (RefVal::Kind) 0;
// This function has a summary. Evaluate the effect of the arguments. // This function has a summary. Evaluate the effect of the arguments.
unsigned idx = 0; unsigned idx = 0;
@ -837,8 +893,7 @@ void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
Expr* ErrorExpr = NULL; Expr* ErrorExpr = NULL;
SymbolID ErrorSym = 0; SymbolID ErrorSym = 0;
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); for (Expr **I = arg_beg, **E = arg_end; I != E; ++I, ++idx) {
I != E; ++I, ++idx) {
RVal V = StateMgr.GetRVal(St, *I); RVal V = StateMgr.GetRVal(St, *I);
@ -857,24 +912,22 @@ void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
} }
} }
} }
else if (isa<LVal>(V)) { // Nuke all arguments passed by reference. else if (isa<LVal>(V)) {
// Nuke all arguments passed by reference.
// FIXME: This is basically copy-and-paste from GRSimpleVals. We
// should compose behavior, not copy it.
StateMgr.Unbind(StVals, cast<LVal>(V)); StateMgr.Unbind(StVals, cast<LVal>(V));
} }
else if (isa<nonlval::LValAsInteger>(V)) else if (isa<nonlval::LValAsInteger>(V))
StateMgr.Unbind(StVals, cast<nonlval::LValAsInteger>(V).getLVal()); StateMgr.Unbind(StVals, cast<nonlval::LValAsInteger>(V).getLVal());
} }
St = StateMgr.getPersistentState(StVals); St = StateMgr.getPersistentState(StVals);
if (hasErr) { if (hasErr) {
ProcessNonLeakError(Dst, Builder, CE, ErrorExpr, Pred, St, ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, Pred, St,
hasErr, ErrorSym); hasErr, ErrorSym);
return; return;
} }
// Finally, consult the summary for the return value. // Finally, consult the summary for the return value.
RetEffect RE = GetRetE(Summ); RetEffect RE = GetRetE(Summ);
@ -882,66 +935,89 @@ void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
switch (RE.getKind()) { switch (RE.getKind()) {
default: default:
assert (false && "Unhandled RetEffect."); break; assert (false && "Unhandled RetEffect."); break;
case RetEffect::NoRet: case RetEffect::NoRet:
// Make up a symbol for the return value (not reference counted). // Make up a symbol for the return value (not reference counted).
// FIXME: This is basically copy-and-paste from GRSimpleVals. We // FIXME: This is basically copy-and-paste from GRSimpleVals. We
// should compose behavior, not copy it. // should compose behavior, not copy it.
if (CE->getType() != Eng.getContext().VoidTy) { if (Ex->getType() != Eng.getContext().VoidTy) {
unsigned Count = Builder.getCurrentBlockCount(); unsigned Count = Builder.getCurrentBlockCount();
SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count); SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(Ex, Count);
RVal X = CE->getType()->isPointerType() RVal X = Ex->getType()->isPointerType()
? cast<RVal>(lval::SymbolVal(Sym)) ? cast<RVal>(lval::SymbolVal(Sym))
: cast<RVal>(nonlval::SymbolVal(Sym)); : cast<RVal>(nonlval::SymbolVal(Sym));
St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false); St = StateMgr.SetRVal(St, Ex, X, Eng.getCFG().isBlkExpr(Ex), false);
} }
break; break;
case RetEffect::Alias: { case RetEffect::Alias: {
unsigned idx = RE.getValue(); unsigned idx = RE.getValue();
assert (idx < CE->getNumArgs()); assert ((arg_end - arg_beg) >= 0);
RVal V = StateMgr.GetRVal(St, CE->getArg(idx)); assert (idx < (unsigned) (arg_end - arg_beg));
St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false); RVal V = StateMgr.GetRVal(St, arg_beg[idx]);
St = StateMgr.SetRVal(St, Ex, V, Eng.getCFG().isBlkExpr(Ex), false);
break; break;
} }
case RetEffect::OwnedSymbol: { case RetEffect::OwnedSymbol: {
unsigned Count = Builder.getCurrentBlockCount(); unsigned Count = Builder.getCurrentBlockCount();
SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count); SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(Ex, Count);
ValueState StImpl = *St; ValueState StImpl = *St;
RefBindings B = GetRefBindings(StImpl); RefBindings B = GetRefBindings(StImpl);
SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned())); SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned()));
St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl), St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
CE, lval::SymbolVal(Sym), Ex, lval::SymbolVal(Sym),
Eng.getCFG().isBlkExpr(CE), false); Eng.getCFG().isBlkExpr(Ex), false);
break; break;
} }
case RetEffect::NotOwnedSymbol: { case RetEffect::NotOwnedSymbol: {
unsigned Count = Builder.getCurrentBlockCount(); unsigned Count = Builder.getCurrentBlockCount();
SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count); SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(Ex, Count);
ValueState StImpl = *St; ValueState StImpl = *St;
RefBindings B = GetRefBindings(StImpl); RefBindings B = GetRefBindings(StImpl);
SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned())); SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl), St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
CE, lval::SymbolVal(Sym), Ex, lval::SymbolVal(Sym),
Eng.getCFG().isBlkExpr(CE), false); Eng.getCFG().isBlkExpr(Ex), false);
break; break;
} }
} }
Builder.MakeNode(Dst, CE, Pred, St); Builder.MakeNode(Dst, Ex, Pred, St);
}
void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder,
CallExpr* CE, RVal L,
ExplodedNode<ValueState>* Pred) {
RetainSummary* Summ = NULL;
// Get the summary.
if (isa<lval::FuncVal>(L)) {
lval::FuncVal FV = cast<lval::FuncVal>(L);
FunctionDecl* FD = FV.getDecl();
Summ = Summaries.getSummary(FD, Eng.getContext());
}
EvalSummary(Dst, Eng, Builder, CE, 0, Summ,
CE->arg_begin(), CE->arg_end(), Pred);
} }
@ -996,7 +1072,7 @@ bool CFRefCount::EvalObjCMessageExprAux(ExplodedNodeSet<ValueState>& Dst,
ObjCMessageExpr* ME, ObjCMessageExpr* ME,
ExplodedNode<ValueState>* Pred) { ExplodedNode<ValueState>* Pred) {
if (GCEnabled) if (isGCEnabled())
return true; return true;
// Handle "toll-free bridging" of calls to "Release" and "Retain". // Handle "toll-free bridging" of calls to "Release" and "Retain".
@ -1344,7 +1420,7 @@ CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
assert (false && "Unhandled CFRef transition."); assert (false && "Unhandled CFRef transition.");
case DoNothing: case DoNothing:
if (!GCEnabled && V.getKind() == RefVal::Released) { if (!isGCEnabled() && V.getKind() == RefVal::Released) {
V = RefVal::makeUseAfterRelease(); V = RefVal::makeUseAfterRelease();
hasErr = V.getKind(); hasErr = V.getKind();
break; break;
@ -1366,7 +1442,7 @@ CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
break; break;
case RefVal::Released: case RefVal::Released:
if (GCEnabled) if (isGCEnabled())
V = RefVal::makeOwned(); V = RefVal::makeOwned();
else { else {
V = RefVal::makeUseAfterRelease(); V = RefVal::makeUseAfterRelease();