[cfe-commits] r49824 - /cfe/trunk/lib/Analysis/CFRefCount.cpp
Ted Kremenek
kremenek at apple.com
Wed Apr 16 15:32:20 PDT 2008
Author: kremenek
Date: Wed Apr 16 17:32:20 2008
New Revision: 49824
URL: http://llvm.org/viewvc/llvm-project?rev=49824&view=rev
Log:
CF ref. count checker: Register memory leaks at the end of a path.
Modified:
cfe/trunk/lib/Analysis/CFRefCount.cpp
Modified: cfe/trunk/lib/Analysis/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFRefCount.cpp?rev=49824&r1=49823&r2=49824&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Wed Apr 16 17:32:20 2008
@@ -472,9 +472,10 @@
}
public:
+
enum Kind { Owned = 0, NotOwned = 1, Released = 2,
- ErrorUseAfterRelease = 3, ErrorReleaseNotOwned = 4 };
-
+ ErrorUseAfterRelease = 3, ErrorReleaseNotOwned = 4,
+ ErrorLeak = 5 };
Kind getKind() const { return (Kind) (Data & 0x7); }
@@ -485,10 +486,16 @@
static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
+ static bool isLeak(Kind k) { return k == ErrorLeak; }
+
bool isOwned() const {
return getKind() == Owned;
}
+ bool isNotOwned() const {
+ return getKind() == NotOwned;
+ }
+
static RefVal makeOwned(unsigned Count = 0) {
return RefVal(Owned, Count);
}
@@ -497,6 +504,7 @@
return RefVal(NotOwned, Count);
}
+ static RefVal makeLeak() { return RefVal(ErrorLeak); }
static RefVal makeReleased() { return RefVal(Released); }
static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); }
static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); }
@@ -528,6 +536,10 @@
Out << "Released";
break;
+ case ErrorLeak:
+ Out << "Leaked";
+ break;
+
case ErrorUseAfterRelease:
Out << "Use-After-Release [ERROR]";
break;
@@ -556,6 +568,10 @@
typedef llvm::DenseMap<GRExprEngine::NodeTy*,Expr*> UseAfterReleasesTy;
typedef llvm::DenseMap<GRExprEngine::NodeTy*,Expr*> ReleasesNotOwnedTy;
+
+ typedef llvm::SmallVector<std::pair<SymbolID, ExplodedNode<ValueState>*>, 2>
+ LeaksTy;
+
class BindingsPrinter : public ValueState::CheckerStatePrinter {
public:
@@ -570,6 +586,7 @@
UseAfterReleasesTy UseAfterReleases;
ReleasesNotOwnedTy ReleasesNotOwned;
+ LeaksTy Leaks;
BindingsPrinter Printer;
@@ -593,12 +610,18 @@
RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E,
RefVal::Kind& hasErr);
- void ProcessError(ExplodedNodeSet<ValueState>& Dst,
- GRStmtNodeBuilder<ValueState>& Builder,
- Expr* NodeExpr, Expr* ErrorExpr,
- ExplodedNode<ValueState>* Pred,
- ValueState* St,
- RefVal::Kind hasErr);
+ void ProcessNonLeakError(ExplodedNodeSet<ValueState>& Dst,
+ GRStmtNodeBuilder<ValueState>& Builder,
+ Expr* NodeExpr, Expr* ErrorExpr,
+ ExplodedNode<ValueState>* Pred,
+ ValueState* St,
+ RefVal::Kind hasErr);
+
+ ValueState* HandleSymbolDeath(ValueStateManager& VMgr, ValueState* St,
+ SymbolID sid, RefVal V, bool& hasLeak);
+
+ ValueState* NukeBinding(ValueStateManager& VMgr, ValueState* St,
+ SymbolID sid);
public:
@@ -691,12 +714,12 @@
return Summ ? Summ->getRet() : RetEffect::MakeNoRet();
}
-void CFRefCount::ProcessError(ExplodedNodeSet<ValueState>& Dst,
- GRStmtNodeBuilder<ValueState>& Builder,
- Expr* NodeExpr, Expr* ErrorExpr,
- ExplodedNode<ValueState>* Pred,
- ValueState* St,
- RefVal::Kind hasErr) {
+void CFRefCount::ProcessNonLeakError(ExplodedNodeSet<ValueState>& Dst,
+ GRStmtNodeBuilder<ValueState>& Builder,
+ Expr* NodeExpr, Expr* ErrorExpr,
+ ExplodedNode<ValueState>* Pred,
+ ValueState* St,
+ RefVal::Kind hasErr) {
Builder.BuildSinks = true;
GRExprEngine::NodeTy* N = Builder.MakeNode(Dst, NodeExpr, Pred, St);
@@ -777,7 +800,7 @@
St = StateMgr.getPersistentState(StVals);
if (hasErr) {
- ProcessError(Dst, Builder, CE, ErrorExpr, Pred, St, hasErr);
+ ProcessNonLeakError(Dst, Builder, CE, ErrorExpr, Pred, St, hasErr);
return;
}
@@ -921,7 +944,7 @@
// Create an error node if it exists.
if (hasErr)
- ProcessError(Dst, Builder, ME, Receiver, Pred, St, hasErr);
+ ProcessNonLeakError(Dst, Builder, ME, Receiver, Pred, St, hasErr);
else
Builder.MakeNode(Dst, ME, Pred, St);
@@ -961,33 +984,63 @@
if (!T)
return;
- // Nuke the binding.
-
- ValueState StImpl = *St;
- StImpl.CheckerState = RefBFactory.Remove(B, Sym).getRoot();
- St = Eng.getStateManager().getPersistentState(StImpl);
+ // Nuke the binding.
+ St = NukeBinding(Eng.getStateManager(), St, Sym);
// Hand of the remaining logic to the parent implementation.
GRSimpleVals::EvalStore(Dst, Eng, Builder, E, Pred, St, TargetLV, Val);
}
+
+ValueState* CFRefCount::NukeBinding(ValueStateManager& VMgr, ValueState* St,
+ SymbolID sid) {
+ ValueState StImpl = *St;
+ RefBindings B = GetRefBindings(StImpl);
+ StImpl.CheckerState = RefBFactory.Remove(B, sid).getRoot();
+ return VMgr.getPersistentState(StImpl);
+}
+
// End-of-path.
-void CFRefCount::EvalEndPath(GRExprEngine& Engine,
+
+
+ValueState* CFRefCount::HandleSymbolDeath(ValueStateManager& VMgr,
+ ValueState* St, SymbolID sid,
+ RefVal V, bool& hasLeak) {
+
+ hasLeak = V.isOwned() || V.isNotOwned() && V.getCount() > 0;
+
+ if (!hasLeak)
+ return NukeBinding(VMgr, St, sid);
+
+ RefBindings B = GetRefBindings(*St);
+ ValueState StImpl = *St;
+ StImpl.CheckerState = RefBFactory.Add(B, sid, RefVal::makeLeak()).getRoot();
+ return VMgr.getPersistentState(StImpl);
+}
+
+void CFRefCount::EvalEndPath(GRExprEngine& Eng,
GREndPathNodeBuilder<ValueState>& Builder) {
- RefBindings B = GetRefBindings(*Builder.getState());
+ ValueState* St = Builder.getState();
+ RefBindings B = GetRefBindings(*St);
- // Scan the set of bindings for symbols that are in the Owned state.
+ llvm::SmallVector<SymbolID, 10> Leaked;
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
- if ((*I).second.isOwned()) {
-
- // FIXME: Register an error with the diagnostic engine. Since we
- // don't have a Stmt* here, we need some extra machinery to get
- // a sourcelocation.
+ for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ bool hasLeak = false;
- }
+ St = HandleSymbolDeath(Eng.getStateManager(), St,
+ (*I).first, (*I).second, hasLeak);
+
+ if (hasLeak) Leaked.push_back((*I).first);
+ }
+
+ ExplodedNode<ValueState>* N = Builder.MakeNode(St);
+
+ for (llvm::SmallVector<SymbolID, 10>::iterator I=Leaked.begin(),
+ E = Leaked.end(); I != E; ++I)
+ Leaks.push_back(std::make_pair(*I, N));
}
More information about the cfe-commits
mailing list