summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2009-02-24 19:15:11 +0000
committerTed Kremenek <kremenek@apple.com>2009-02-24 19:15:11 +0000
commitc52f9394ce1dd59a4f57e3f6cef34fb7679e3a5a (patch)
treeac82ae3a8a977a32d4e7a338d7c5a7450bc08b5f
parent5bf00893b68f06cd6112c51d0df676ec8ba2460f (diff)
downloadbcm5719-llvm-c52f9394ce1dd59a4f57e3f6cef34fb7679e3a5a.tar.gz
bcm5719-llvm-c52f9394ce1dd59a4f57e3f6cef34fb7679e3a5a.zip
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. llvm-svn: 65384
-rw-r--r--clang/lib/Analysis/CFRefCount.cpp108
1 files changed, 38 insertions, 70 deletions
diff --git a/clang/lib/Analysis/CFRefCount.cpp b/clang/lib/Analysis/CFRefCount.cpp
index 5a3e9be0cb3..3a88877ba54 100644
--- a/clang/lib/Analysis/CFRefCount.cpp
+++ b/clang/lib/Analysis/CFRefCount.cpp
@@ -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 {
-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 AutoRCIndex = 0;
static int AutoRBIndex = 0;
-// We can use 'AutoreleaseBindings' directly as the tag class into the GDM sinc
-// it is an ImmutableMap based on two types private to this source file.
+namespace { class VISIBILITY_HIDDEN AutoreleasePoolContents {}; }
+namespace { class VISIBILITY_HIDDEN AutoreleaseBindings {}; }
+
namespace clang {
- template<>
- struct GRStateTrait<AutoreleaseBindings>
- : public GRStatePartialTrait<AutoreleaseBindings> {
- static inline void* GDMIndex() { return &AutoRBIndex; }
- };
-}
+template<> struct GRStateTrait<AutoreleaseBindings>
+ : public GRStatePartialTrait<ARStack> {
+ static inline void* GDMIndex() { return &AutoRBIndex; }
+};
+
+template<> struct GRStateTrait<AutoreleasePoolContents>
+ : public GRStatePartialTrait<ARPoolContents> {
+ static inline void* GDMIndex() { return &AutoRCIndex; }
+};
+} // end clang namespace
//===----------------------------------------------------------------------===//
// Transfer functions.
@@ -1430,23 +1404,15 @@ private:
RetainSummaryManager Summaries;
SummaryLogTy SummaryLog;
const LangOptions& LOpts;
+ ARCounts::Factory ARCountFactory;
BugType *useAfterRelease, *releaseNotOwned;
BugType *leakWithinFunction, *leakAtReturn;
BugReporter *BR;
- RefBindings Update(RefBindings B, SymbolRef sym, RefVal V, ArgEffect E,
- RefVal::Kind& hasErr, RefBindings::Factory& RefBFactory);
-
- 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;
- }
-
+ GRStateRef Update(GRStateRef state, SymbolRef sym, RefVal V, ArgEffect E,
+ RefVal::Kind& hasErr);
+
void ProcessNonLeakError(ExplodedNodeSet<GRState>& Dst,
GRStmtNodeBuilder<GRState>& Builder,
Expr* NodeExpr, Expr* ErrorExpr,
@@ -1458,8 +1424,7 @@ private:
HandleSymbolDeath(GRStateManager& VMgr, const GRState* St,
const Decl* CD, SymbolRef sid, RefVal V, bool& hasLeak);
-public:
-
+public:
CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
: Summaries(Ctx, gcenabled),
LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
@@ -1633,12 +1598,14 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
if (isa<loc::SymbolVal>(V)) {
SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
- if (RefBindings::data_type* T = state.get<RefBindings>(Sym))
- if (Update(state, Sym, *T, GetArgE(Summ, idx), hasErr)) {
+ if (RefBindings::data_type* T = state.get<RefBindings>(Sym)) {
+ state = Update(state, Sym, *T, GetArgE(Summ, idx), hasErr);
+ if (hasErr) {
ErrorExpr = *I;
ErrorSym = Sym;
break;
}
+ }
}
else if (isa<Loc>(V)) {
if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) {
@@ -1711,11 +1678,13 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
SVal V = state.GetSVal(Receiver);
if (isa<loc::SymbolVal>(V)) {
SymbolRef Sym = cast<loc::SymbolVal>(V).getSymbol();
- if (const RefVal* T = state.get<RefBindings>(Sym))
- if (Update(state, Sym, *T, GetReceiverE(Summ), hasErr)) {
+ if (const RefVal* T = state.get<RefBindings>(Sym)) {
+ state = Update(state, Sym, *T, GetReceiverE(Summ), hasErr);
+ if (hasErr) {
ErrorExpr = Receiver;
ErrorSym = Sym;
}
+ }
}
}
@@ -2073,10 +2042,9 @@ const GRState* CFRefCount::EvalAssume(GRStateManager& VMgr,
return state;
}
-RefBindings CFRefCount::Update(RefBindings B, SymbolRef sym,
- RefVal V, ArgEffect E,
- RefVal::Kind& hasErr,
- RefBindings::Factory& RefBFactory) {
+GRStateRef CFRefCount::Update(GRStateRef state, SymbolRef sym,
+ RefVal V, ArgEffect E,
+ RefVal::Kind& hasErr) {
// In GC mode [... release] and [... retain] do nothing.
switch (E) {
@@ -2107,13 +2075,13 @@ RefBindings CFRefCount::Update(RefBindings B, SymbolRef sym,
hasErr = V.getKind();
break;
}
- return B;
+ return state;
case Autorelease:
- if (isGCEnabled()) return B;
+ if (isGCEnabled()) return state;
// Fall-through.
case StopTracking:
- return RefBFactory.Remove(B, sym);
+ return state.remove<RefBindings>(sym);
case IncRef:
switch (V.getKind()) {
@@ -2165,7 +2133,7 @@ RefBindings CFRefCount::Update(RefBindings B, SymbolRef sym,
}
break;
}
- return RefBFactory.Add(B, sym, V);
+ return state.set<RefBindings>(sym, V);
}
//===----------------------------------------------------------------------===//
OpenPOWER on IntegriCloud