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:
parent
4ead264c08
commit
00daccdd2a
|
|
@ -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();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue