aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/MallocChecker.cpp
diff options
context:
space:
mode:
authorZhongxing Xu <xuzhongxing@gmail.com>2009-11-17 07:54:15 +0000
committerZhongxing Xu <xuzhongxing@gmail.com>2009-11-17 07:54:15 +0000
commit243fde9f549a8f5f000c4baccb572dd0b7266a41 (patch)
treeaae9e699e12c5e84023a28bcc836690152b94bea /lib/Analysis/MallocChecker.cpp
parent314be4e7d8ef86202b0ec8e9ff0dcef853db3320 (diff)
Add EvalEndPath interface to Checker. Now we can check memory leaked at the
end of the path. Need to unify interfaces. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89063 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/MallocChecker.cpp')
-rw-r--r--lib/Analysis/MallocChecker.cpp72
1 files changed, 52 insertions, 20 deletions
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp
index 6129358cf7..fdd6a3d026 100644
--- a/lib/Analysis/MallocChecker.cpp
+++ b/lib/Analysis/MallocChecker.cpp
@@ -22,8 +22,28 @@ using namespace clang;
namespace {
-enum RefState {
- Allocated, Released, Escaped
+struct RefState {
+ enum Kind { Allocated, Released, Escaped } K;
+ const Stmt *S;
+
+ RefState(Kind k, const Stmt *s) : K(k), S(s) {}
+
+ bool isAllocated() const { return K == Allocated; }
+ bool isReleased() const { return K == Released; }
+ bool isEscaped() const { return K == Escaped; }
+
+ bool operator==(const RefState &X) const {
+ return K == X.K && S == X.S;
+ }
+
+ static RefState getAllocated(const Stmt *s) { return RefState(Allocated, s); }
+ static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
+ static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(K);
+ ID.AddPointer(S);
+ }
};
class VISIBILITY_HIDDEN RegionState {};
@@ -39,25 +59,15 @@ public:
static void *getTag();
void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
+ void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
private:
void MallocMem(CheckerContext &C, const CallExpr *CE);
void FreeMem(CheckerContext &C, const CallExpr *CE);
};
}
-namespace llvm {
- template<> struct FoldingSetTrait<RefState> {
- static void Profile(const RefState &X, FoldingSetNodeID &ID) {
- ID.AddInteger(X);
- }
- static void Profile(RefState &X, FoldingSetNodeID &ID) {
- ID.AddInteger(X);
- }
- };
-}
-
namespace clang {
- template<>
+ template <>
struct GRStateTrait<RegionState>
: public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > {
static void *GDMIndex() { return MallocChecker::getTag(); }
@@ -101,7 +111,8 @@ void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
SymbolRef Sym = CallVal.getAsLocSymbol();
assert(Sym);
// Set the symbol's state to Allocated.
- const GRState *AllocState = state->set<RegionState>(Sym, Allocated);
+ const GRState *AllocState
+ = state->set<RegionState>(Sym, RefState::getAllocated(CE));
C.addTransition(C.GenerateNode(CE, AllocState));
}
@@ -115,7 +126,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
assert(RS);
// Check double free.
- if (*RS == Released) {
+ if (RS->isReleased()) {
ExplodedNode *N = C.GenerateNode(CE, true);
if (N) {
if (!BT_DoubleFree)
@@ -130,7 +141,8 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
}
// Normal free.
- const GRState *FreedState = state->set<RegionState>(Sym, Released);
+ const GRState *FreedState
+ = state->set<RegionState>(Sym, RefState::getReleased(CE));
C.addTransition(C.GenerateNode(CE, FreedState));
}
@@ -144,17 +156,37 @@ void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
if (!RS)
return;
- if (*RS == Allocated) {
+ if (RS->isAllocated()) {
ExplodedNode *N = C.GenerateNode(S, true);
if (N) {
if (!BT_Leak)
BT_Leak = new BuiltinBug("Memory leak",
"Allocated memory never released. Potential memory leak.");
// FIXME: where it is allocated.
- BugReport *R = new BugReport(*BT_Leak,
- BT_Leak->getDescription(), N);
+ BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
C.EmitReport(R);
}
}
}
}
+
+void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
+ GRExprEngine &Eng) {
+ const GRState *state = B.getState();
+ typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap;
+ SymMap M = state->get<RegionState>();
+
+ for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+ RefState RS = I->second;
+ if (RS.isAllocated()) {
+ ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+ if (N) {
+ if (!BT_Leak)
+ BT_Leak = new BuiltinBug("Memory leak",
+ "Allocated memory never released. Potential memory leak.");
+ BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
+ Eng.getBugReporter().EmitReport(R);
+ }
+ }
+ }
+}