aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/CFRefCount.cpp
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-06-15 23:02:42 +0000
committerJohn McCall <rjmccall@apple.com>2011-06-15 23:02:42 +0000
commitf85e193739c953358c865005855253af4f68a497 (patch)
treee242284beb7fd2b88a2f3ce08644585497d5910d /lib/StaticAnalyzer/Core/CFRefCount.cpp
parent204e13395d83524e9a557c3f3fd6df2e2f353b9d (diff)
Automatic Reference Counting.
Language-design credit goes to a lot of people, but I particularly want to single out Blaine Garst and Patrick Beard for their contributions. Compiler implementation credit goes to Argyrios, Doug, Fariborz, and myself, in no particular order. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133103 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/CFRefCount.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp107
1 files changed, 90 insertions, 17 deletions
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp
index 0512e2f08d..33118fa901 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp
@@ -126,6 +126,7 @@ public:
/// ArgEffect is used to summarize a function/method call's effect on a
/// particular argument.
enum ArgEffect { Autorelease, Dealloc, DecRef, DecRefMsg, DoNothing,
+ DecRefBridgedTransfered,
DoNothingByRef, IncRefMsg, IncRef, MakeCollectable, MayEscape,
NewAutoreleasePool, SelfOwn, StopTracking };
@@ -148,7 +149,8 @@ namespace {
class RetEffect {
public:
enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol,
- NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias,
+ NotOwnedSymbol, GCNotOwnedSymbol, ARCNotOwnedSymbol,
+ ReceiverAlias,
OwnedWhenTrackedReceiver };
enum ObjKind { CF, ObjC, AnyObj };
@@ -195,7 +197,9 @@ public:
static RetEffect MakeGCNotOwned() {
return RetEffect(GCNotOwnedSymbol, ObjC);
}
-
+ static RetEffect MakeARCNotOwned() {
+ return RetEffect(ARCNotOwnedSymbol, ObjC);
+ }
static RetEffect MakeNoRet() {
return RetEffect(NoRet);
}
@@ -636,6 +640,9 @@ class RetainSummaryManager {
/// GCEnabled - Records whether or not the analyzed code runs in GC mode.
const bool GCEnabled;
+ /// Records whether or not the analyzed code runs in ARC mode.
+ const bool ARCEnabled;
+
/// FuncSummaries - A map from FunctionDecls to summaries.
FuncSummariesTy FuncSummaries;
@@ -788,14 +795,20 @@ private:
public:
- RetainSummaryManager(ASTContext& ctx, bool gcenabled)
+ RetainSummaryManager(ASTContext& ctx, bool gcenabled, bool usesARC)
: Ctx(ctx),
CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")),
- GCEnabled(gcenabled), AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
- ObjCAllocRetE(gcenabled ? RetEffect::MakeGCNotOwned()
- : RetEffect::MakeOwned(RetEffect::ObjC, true)),
- ObjCInitRetE(gcenabled ? RetEffect::MakeGCNotOwned()
- : RetEffect::MakeOwnedWhenTrackedReceiver()),
+ GCEnabled(gcenabled),
+ ARCEnabled(usesARC),
+ AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
+ ObjCAllocRetE(gcenabled
+ ? RetEffect::MakeGCNotOwned()
+ : (usesARC ? RetEffect::MakeARCNotOwned()
+ : RetEffect::MakeOwned(RetEffect::ObjC, true))),
+ ObjCInitRetE(gcenabled
+ ? RetEffect::MakeGCNotOwned()
+ : (usesARC ? RetEffect::MakeARCNotOwned()
+ : RetEffect::MakeOwnedWhenTrackedReceiver())),
DefaultSummary(AF.getEmptyMap() /* per-argument effects (none) */,
RetEffect::MakeNoRet() /* return effect */,
MayEscape, /* default argument effect */
@@ -871,6 +884,10 @@ public:
bool isGCEnabled() const { return GCEnabled; }
+ bool isARCEnabled() const { return ARCEnabled; }
+
+ bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; }
+
RetainSummary *copySummary(RetainSummary *OldSumm) {
RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
new (Summ) RetainSummary(*OldSumm);
@@ -1654,7 +1671,6 @@ public:
const char* nl, const char* sep);
};
-private:
typedef llvm::DenseMap<const ExplodedNode*, const RetainSummary*>
SummaryLogTy;
@@ -1691,7 +1707,7 @@ private:
public:
CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
- : Summaries(Ctx, gcenabled),
+ : Summaries(Ctx, gcenabled, (bool)lopts.ObjCAutoRefCount),
LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
deallocGC(0), deallocNotOwned(0),
leakWithinFunction(0), leakAtReturn(0), overAutorelease(0),
@@ -1706,6 +1722,8 @@ public:
}
bool isGCEnabled() const { return Summaries.isGCEnabled(); }
+ bool isARCorGCEnabled() const { return Summaries.isARCorGCEnabled(); }
+
const LangOptions& getLangOptions() const { return LOpts; }
const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const {
@@ -2777,6 +2795,7 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
}
case RetEffect::GCNotOwnedSymbol:
+ case RetEffect::ARCNotOwnedSymbol:
case RetEffect::NotOwnedSymbol: {
unsigned Count = Builder.getCurrentBlockCount();
SValBuilder &svalBuilder = Eng.getSValBuilder();
@@ -3103,8 +3122,8 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
// In GC mode [... release] and [... retain] do nothing.
switch (E) {
default: break;
- case IncRefMsg: E = isGCEnabled() ? DoNothing : IncRef; break;
- case DecRefMsg: E = isGCEnabled() ? DoNothing : DecRef; break;
+ case IncRefMsg: E = isARCorGCEnabled() ? DoNothing : IncRef; break;
+ case DecRefMsg: E = isARCorGCEnabled() ? DoNothing : DecRef; break;
case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break;
case NewAutoreleasePool: E = isGCEnabled() ? DoNothing :
NewAutoreleasePool; break;
@@ -3118,9 +3137,13 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
}
switch (E) {
- default:
- assert (false && "Unhandled CFRef transition.");
-
+ case DecRefMsg:
+ case IncRefMsg:
+ case MakeCollectable:
+ assert(false &&
+ "DecRefMsg/IncRefMsg/MakeCollectable already transformed");
+ return state;
+
case Dealloc:
// Any use of -dealloc in GC is *bad*.
if (isGCEnabled()) {
@@ -3193,6 +3216,7 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
V = V ^ RefVal::NotOwned;
// Fall-through.
case DecRef:
+ case DecRefBridgedTransfered:
switch (V.getKind()) {
default:
// case 'RefVal::Released' handled above.
@@ -3200,7 +3224,9 @@ const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
case RefVal::Owned:
assert(V.getCount() > 0);
- if (V.getCount() == 1) V = V ^ RefVal::Released;
+ if (V.getCount() == 1)
+ V = V ^ (E == DecRefBridgedTransfered ?
+ RefVal::NotOwned : RefVal::Released);
V = V - 1;
break;
@@ -3468,7 +3494,9 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
namespace {
class RetainReleaseChecker
- : public Checker< check::PostStmt<BlockExpr>, check::RegionChanges > {
+ : public Checker< check::PostStmt<BlockExpr>,
+ check::PostStmt<CastExpr>,
+ check::RegionChanges > {
public:
bool wantsRegionUpdate;
@@ -3476,6 +3504,9 @@ public:
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
+
+ void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
+
const GRState *checkRegionChanges(const GRState *state,
const StoreManager::InvalidatedSymbols *invalidated,
const MemRegion * const *begin,
@@ -3545,6 +3576,48 @@ void RetainReleaseChecker::checkPostStmt(const BlockExpr *BE,
C.addTransition(state);
}
+void RetainReleaseChecker::checkPostStmt(const CastExpr *CE,
+ CheckerContext &C) const {
+ const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
+ if (!BE)
+ return;
+
+ ArgEffect AE;
+
+ switch (BE->getBridgeKind()) {
+ case clang::OBC_Bridge:
+ // Do nothing.
+ return;
+ case clang::OBC_BridgeRetained:
+ AE = IncRef;
+ break;
+ case clang::OBC_BridgeTransfer:
+ AE = DecRefBridgedTransfered;
+ break;
+ }
+
+ const GRState *state = C.getState();
+ SymbolRef Sym = state->getSVal(CE).getAsLocSymbol();
+ if (!Sym)
+ return;
+ const RefVal* T = state->get<RefBindings>(Sym);
+ if (!T)
+ return;
+
+ // This is gross. Once the checker and CFRefCount are unified,
+ // this will go away.
+ CFRefCount &cf = static_cast<CFRefCount&>(C.getEngine().getTF());
+ RefVal::Kind hasErr = (RefVal::Kind) 0;
+ state = cf.Update(state, Sym, *T, AE, hasErr);
+
+ if (hasErr) {
+
+ return;
+ }
+
+ C.generateNode(state);
+}
+
//===----------------------------------------------------------------------===//
// Transfer function creation for external clients.
//===----------------------------------------------------------------------===//