зеркало из https://github.com/microsoft/clang-1.git
retain/release checker:
- For autorelease pool tracking, keep information about the stack of pools separate from their contents. Also, keep track of the number of times an autorelease pool will send the "release" message to an object when the pool is destroyed. - Update CFRefCount::Update to return a new state instead of a reference count binding. This will allow us to implement more complicated semantics with autorelease pools. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65384 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
d01b669f26
Коммит
4d3957da69
|
@ -1358,56 +1358,30 @@ namespace clang {
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// ARBindings - State used to track objects in autorelease pools.
|
// AutoreleaseBindings - State used to track objects in autorelease pools.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
typedef llvm::ImmutableMap<SymbolRef, unsigned> ARCounts;
|
||||||
|
typedef llvm::ImmutableMap<SymbolRef, ARCounts> ARPoolContents;
|
||||||
|
typedef llvm::ImmutableList<SymbolRef> ARStack;
|
||||||
|
|
||||||
namespace {
|
static int AutoRCIndex = 0;
|
||||||
class VISIBILITY_HIDDEN AutoreleasePoolID {
|
|
||||||
unsigned short PoolLevel;
|
|
||||||
SymbolRef Sym;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AutoreleasePoolID() : PoolLevel(0) {}
|
|
||||||
AutoreleasePoolID(unsigned short poolLevel, SymbolRef sym)
|
|
||||||
: PoolLevel(poolLevel), Sym(Sym) {}
|
|
||||||
|
|
||||||
bool operator<(const AutoreleasePoolID &X) const {
|
|
||||||
assert(!(PoolLevel == X.PoolLevel) || Sym == X.Sym);
|
|
||||||
return PoolLevel < X.PoolLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const AutoreleasePoolID &X) const {
|
|
||||||
assert(!(PoolLevel == X.PoolLevel) || Sym == X.Sym);
|
|
||||||
return PoolLevel == X.PoolLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool matches(SymbolRef sym) {
|
|
||||||
return Sym.isInitialized() ? Sym == sym : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Profile(llvm::FoldingSetNodeID& ID, const AutoreleasePoolID& AI) {
|
|
||||||
ID.AddInteger(AI.PoolLevel);
|
|
||||||
if (AI.Sym.isInitialized()) ID.Add(AI.Sym);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef llvm::ImmutableSet<SymbolRef> AutoreleasePoolContents;
|
|
||||||
typedef llvm::ImmutableMap<AutoreleasePoolID, AutoreleasePoolContents>
|
|
||||||
AutoreleaseBindings;
|
|
||||||
|
|
||||||
static int AutoRBIndex = 0;
|
static int AutoRBIndex = 0;
|
||||||
|
|
||||||
// We can use 'AutoreleaseBindings' directly as the tag class into the GDM sinc
|
namespace { class VISIBILITY_HIDDEN AutoreleasePoolContents {}; }
|
||||||
// it is an ImmutableMap based on two types private to this source file.
|
namespace { class VISIBILITY_HIDDEN AutoreleaseBindings {}; }
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
template<>
|
template<> struct GRStateTrait<AutoreleaseBindings>
|
||||||
struct GRStateTrait<AutoreleaseBindings>
|
: public GRStatePartialTrait<ARStack> {
|
||||||
: public GRStatePartialTrait<AutoreleaseBindings> {
|
|
||||||
static inline void* GDMIndex() { return &AutoRBIndex; }
|
static inline void* GDMIndex() { return &AutoRBIndex; }
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
template<> struct GRStateTrait<AutoreleasePoolContents>
|
||||||
|
: public GRStatePartialTrait<ARPoolContents> {
|
||||||
|
static inline void* GDMIndex() { return &AutoRCIndex; }
|
||||||
|
};
|
||||||
|
} // end clang namespace
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Transfer functions.
|
// Transfer functions.
|
||||||
|
@ -1430,22 +1404,14 @@ private:
|
||||||
RetainSummaryManager Summaries;
|
RetainSummaryManager Summaries;
|
||||||
SummaryLogTy SummaryLog;
|
SummaryLogTy SummaryLog;
|
||||||
const LangOptions& LOpts;
|
const LangOptions& LOpts;
|
||||||
|
ARCounts::Factory ARCountFactory;
|
||||||
|
|
||||||
BugType *useAfterRelease, *releaseNotOwned;
|
BugType *useAfterRelease, *releaseNotOwned;
|
||||||
BugType *leakWithinFunction, *leakAtReturn;
|
BugType *leakWithinFunction, *leakAtReturn;
|
||||||
BugReporter *BR;
|
BugReporter *BR;
|
||||||
|
|
||||||
RefBindings Update(RefBindings B, SymbolRef sym, RefVal V, ArgEffect E,
|
GRStateRef Update(GRStateRef state, SymbolRef sym, RefVal V, ArgEffect E,
|
||||||
RefVal::Kind& hasErr, RefBindings::Factory& RefBFactory);
|
RefVal::Kind& hasErr);
|
||||||
|
|
||||||
RefVal::Kind& Update(GRStateRef& state, SymbolRef sym, RefVal V,
|
|
||||||
ArgEffect E, RefVal::Kind& hasErr) {
|
|
||||||
|
|
||||||
state = state.set<RefBindings>(Update(state.get<RefBindings>(), sym, V,
|
|
||||||
E, hasErr,
|
|
||||||
state.get_context<RefBindings>()));
|
|
||||||
return hasErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessNonLeakError(ExplodedNodeSet<GRState>& Dst,
|
void ProcessNonLeakError(ExplodedNodeSet<GRState>& Dst,
|
||||||
GRStmtNodeBuilder<GRState>& Builder,
|
GRStmtNodeBuilder<GRState>& Builder,
|
||||||
|
@ -1459,7 +1425,6 @@ private:
|
||||||
const Decl* CD, SymbolRef sid, RefVal V, bool& hasLeak);
|
const Decl* CD, SymbolRef sid, RefVal V, bool& hasLeak);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
|
CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
|
||||||
: Summaries(Ctx, gcenabled),
|
: Summaries(Ctx, gcenabled),
|
||||||
LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
|
LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
|
||||||
|
@ -1633,13 +1598,15 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
|
||||||
|
|
||||||
if (isa<loc::SymbolVal>(V)) {
|
if (isa<loc::SymbolVal>(V)) {
|
||||||
SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
|
SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
|
||||||
if (RefBindings::data_type* T = state.get<RefBindings>(Sym))
|
if (RefBindings::data_type* T = state.get<RefBindings>(Sym)) {
|
||||||
if (Update(state, Sym, *T, GetArgE(Summ, idx), hasErr)) {
|
state = Update(state, Sym, *T, GetArgE(Summ, idx), hasErr);
|
||||||
|
if (hasErr) {
|
||||||
ErrorExpr = *I;
|
ErrorExpr = *I;
|
||||||
ErrorSym = Sym;
|
ErrorSym = Sym;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (isa<Loc>(V)) {
|
else if (isa<Loc>(V)) {
|
||||||
if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) {
|
if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) {
|
||||||
|
|
||||||
|
@ -1711,13 +1678,15 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
|
||||||
SVal V = state.GetSVal(Receiver);
|
SVal V = state.GetSVal(Receiver);
|
||||||
if (isa<loc::SymbolVal>(V)) {
|
if (isa<loc::SymbolVal>(V)) {
|
||||||
SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
|
SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
|
||||||
if (const RefVal* T = state.get<RefBindings>(Sym))
|
if (const RefVal* T = state.get<RefBindings>(Sym)) {
|
||||||
if (Update(state, Sym, *T, GetReceiverE(Summ), hasErr)) {
|
state = Update(state, Sym, *T, GetReceiverE(Summ), hasErr);
|
||||||
|
if (hasErr) {
|
||||||
ErrorExpr = Receiver;
|
ErrorExpr = Receiver;
|
||||||
ErrorSym = Sym;
|
ErrorSym = Sym;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Process any errors.
|
// Process any errors.
|
||||||
if (hasErr) {
|
if (hasErr) {
|
||||||
|
@ -2073,10 +2042,9 @@ const GRState* CFRefCount::EvalAssume(GRStateManager& VMgr,
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefBindings CFRefCount::Update(RefBindings B, SymbolRef sym,
|
GRStateRef CFRefCount::Update(GRStateRef state, SymbolRef sym,
|
||||||
RefVal V, ArgEffect E,
|
RefVal V, ArgEffect E,
|
||||||
RefVal::Kind& hasErr,
|
RefVal::Kind& hasErr) {
|
||||||
RefBindings::Factory& RefBFactory) {
|
|
||||||
|
|
||||||
// In GC mode [... release] and [... retain] do nothing.
|
// In GC mode [... release] and [... retain] do nothing.
|
||||||
switch (E) {
|
switch (E) {
|
||||||
|
@ -2107,13 +2075,13 @@ RefBindings CFRefCount::Update(RefBindings B, SymbolRef sym,
|
||||||
hasErr = V.getKind();
|
hasErr = V.getKind();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return B;
|
return state;
|
||||||
|
|
||||||
case Autorelease:
|
case Autorelease:
|
||||||
if (isGCEnabled()) return B;
|
if (isGCEnabled()) return state;
|
||||||
// Fall-through.
|
// Fall-through.
|
||||||
case StopTracking:
|
case StopTracking:
|
||||||
return RefBFactory.Remove(B, sym);
|
return state.remove<RefBindings>(sym);
|
||||||
|
|
||||||
case IncRef:
|
case IncRef:
|
||||||
switch (V.getKind()) {
|
switch (V.getKind()) {
|
||||||
|
@ -2165,7 +2133,7 @@ RefBindings CFRefCount::Update(RefBindings B, SymbolRef sym,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return RefBFactory.Add(B, sym, V);
|
return state.set<RefBindings>(sym, V);
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
Загрузка…
Ссылка в новой задаче