blob: 204c7b320e65760b28aafadfbdc39824bd6c1e73 [file] [log] [blame]
Zhongxing Xu589c0f22009-11-12 08:38:56 +00001//=== MallocChecker.cpp - A malloc/free checker -------------------*- C++ -*--//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines malloc/free checker, which checks for potential memory
11// leaks, double free, and use-after-free problems.
12//
13//===----------------------------------------------------------------------===//
14
Zhongxing Xu7b760962009-11-13 07:25:27 +000015#include "GRExprEngineExperimentalChecks.h"
Zhongxing Xu589c0f22009-11-12 08:38:56 +000016#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
17#include "clang/Analysis/PathSensitive/GRState.h"
18#include "clang/Analysis/PathSensitive/GRStateTrait.h"
19#include "clang/Analysis/PathSensitive/SymbolManager.h"
20#include "llvm/ADT/ImmutableMap.h"
21using namespace clang;
22
23namespace {
24
Zhongxing Xu243fde92009-11-17 07:54:15 +000025struct RefState {
26 enum Kind { Allocated, Released, Escaped } K;
27 const Stmt *S;
28
29 RefState(Kind k, const Stmt *s) : K(k), S(s) {}
30
31 bool isAllocated() const { return K == Allocated; }
32 bool isReleased() const { return K == Released; }
33 bool isEscaped() const { return K == Escaped; }
34
35 bool operator==(const RefState &X) const {
36 return K == X.K && S == X.S;
37 }
38
39 static RefState getAllocated(const Stmt *s) { return RefState(Allocated, s); }
40 static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
41 static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); }
42
43 void Profile(llvm::FoldingSetNodeID &ID) const {
44 ID.AddInteger(K);
45 ID.AddPointer(S);
46 }
Zhongxing Xu589c0f22009-11-12 08:38:56 +000047};
48
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000049class RegionState {};
Zhongxing Xu589c0f22009-11-12 08:38:56 +000050
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000051class MallocChecker : public CheckerVisitor<MallocChecker> {
Zhongxing Xu589c0f22009-11-12 08:38:56 +000052 BuiltinBug *BT_DoubleFree;
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +000053 BuiltinBug *BT_Leak;
Zhongxing Xu589c0f22009-11-12 08:38:56 +000054 IdentifierInfo *II_malloc;
55 IdentifierInfo *II_free;
56
57public:
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +000058 MallocChecker() : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0) {}
Zhongxing Xu589c0f22009-11-12 08:38:56 +000059 static void *getTag();
60 void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu7b760962009-11-13 07:25:27 +000061 void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
Zhongxing Xu243fde92009-11-17 07:54:15 +000062 void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
Zhongxing Xu4985e3e2009-11-17 08:58:18 +000063 void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
Zhongxing Xu7b760962009-11-13 07:25:27 +000064private:
Zhongxing Xu589c0f22009-11-12 08:38:56 +000065 void MallocMem(CheckerContext &C, const CallExpr *CE);
66 void FreeMem(CheckerContext &C, const CallExpr *CE);
67};
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000068} // end anonymous namespace
Zhongxing Xu589c0f22009-11-12 08:38:56 +000069
Zhongxing Xu589c0f22009-11-12 08:38:56 +000070namespace clang {
Zhongxing Xu243fde92009-11-17 07:54:15 +000071 template <>
Zhongxing Xu589c0f22009-11-12 08:38:56 +000072 struct GRStateTrait<RegionState>
73 : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > {
74 static void *GDMIndex() { return MallocChecker::getTag(); }
75 };
76}
77
Zhongxing Xu7b760962009-11-13 07:25:27 +000078void clang::RegisterMallocChecker(GRExprEngine &Eng) {
79 Eng.registerCheck(new MallocChecker());
80}
81
Zhongxing Xu589c0f22009-11-12 08:38:56 +000082void *MallocChecker::getTag() {
83 static int x;
84 return &x;
85}
86
87void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
88 const FunctionDecl *FD = CE->getDirectCallee();
89 if (!FD)
90 return;
91
92 ASTContext &Ctx = C.getASTContext();
93 if (!II_malloc)
94 II_malloc = &Ctx.Idents.get("malloc");
95 if (!II_free)
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +000096 II_free = &Ctx.Idents.get("free");
Zhongxing Xu589c0f22009-11-12 08:38:56 +000097
98 if (FD->getIdentifier() == II_malloc) {
99 MallocMem(C, CE);
100 return;
101 }
102
103 if (FD->getIdentifier() == II_free) {
104 FreeMem(C, CE);
105 return;
106 }
107}
108
109void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
110 const GRState *state = C.getState();
111 SVal CallVal = state->getSVal(CE);
112 SymbolRef Sym = CallVal.getAsLocSymbol();
113 assert(Sym);
114 // Set the symbol's state to Allocated.
Ted Kremenek19d67b52009-11-23 22:22:01 +0000115 C.addTransition(state->set<RegionState>(Sym, RefState::getAllocated(CE)));
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000116}
117
118void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
119 const GRState *state = C.getState();
120 SVal ArgVal = state->getSVal(CE->getArg(0));
121 SymbolRef Sym = ArgVal.getAsLocSymbol();
122 assert(Sym);
123
124 const RefState *RS = state->get<RegionState>(Sym);
125 assert(RS);
126
127 // Check double free.
Zhongxing Xu243fde92009-11-17 07:54:15 +0000128 if (RS->isReleased()) {
Ted Kremenek19d67b52009-11-23 22:22:01 +0000129 ExplodedNode *N = C.GenerateSink();
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000130 if (N) {
131 if (!BT_DoubleFree)
132 BT_DoubleFree = new BuiltinBug("Double free",
133 "Try to free a memory block that has been released");
134 // FIXME: should find where it's freed last time.
135 BugReport *R = new BugReport(*BT_DoubleFree,
Benjamin Kramerd02e2322009-11-14 12:08:24 +0000136 BT_DoubleFree->getDescription(), N);
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000137 C.EmitReport(R);
138 }
139 return;
140 }
141
142 // Normal free.
Zhongxing Xu243fde92009-11-17 07:54:15 +0000143 const GRState *FreedState
144 = state->set<RegionState>(Sym, RefState::getReleased(CE));
Ted Kremenek19d67b52009-11-23 22:22:01 +0000145 C.addTransition(FreedState);
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000146}
Zhongxing Xu7b760962009-11-13 07:25:27 +0000147
148void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
149 SymbolReaper &SymReaper) {
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000150 for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
151 E = SymReaper.dead_end(); I != E; ++I) {
152 SymbolRef Sym = *I;
153 const GRState *state = C.getState();
154 const RefState *RS = state->get<RegionState>(Sym);
155 if (!RS)
156 return;
157
Zhongxing Xu243fde92009-11-17 07:54:15 +0000158 if (RS->isAllocated()) {
Ted Kremenek19d67b52009-11-23 22:22:01 +0000159 ExplodedNode *N = C.GenerateSink();
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000160 if (N) {
161 if (!BT_Leak)
162 BT_Leak = new BuiltinBug("Memory leak",
163 "Allocated memory never released. Potential memory leak.");
164 // FIXME: where it is allocated.
Zhongxing Xu243fde92009-11-17 07:54:15 +0000165 BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000166 C.EmitReport(R);
167 }
168 }
169 }
Zhongxing Xu7b760962009-11-13 07:25:27 +0000170}
Zhongxing Xu243fde92009-11-17 07:54:15 +0000171
172void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
173 GRExprEngine &Eng) {
Zhongxing Xuf605aae2009-11-22 13:22:34 +0000174 SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
Zhongxing Xu243fde92009-11-17 07:54:15 +0000175 const GRState *state = B.getState();
176 typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap;
177 SymMap M = state->get<RegionState>();
178
179 for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
180 RefState RS = I->second;
181 if (RS.isAllocated()) {
182 ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
183 if (N) {
184 if (!BT_Leak)
185 BT_Leak = new BuiltinBug("Memory leak",
186 "Allocated memory never released. Potential memory leak.");
187 BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
188 Eng.getBugReporter().EmitReport(R);
189 }
190 }
191 }
192}
Zhongxing Xu4985e3e2009-11-17 08:58:18 +0000193
194void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
195 const Expr *RetE = S->getRetValue();
196 if (!RetE)
197 return;
198
199 const GRState *state = C.getState();
200
201 SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
202
203 if (!Sym)
204 return;
205
206 const RefState *RS = state->get<RegionState>(Sym);
207 if (!RS)
208 return;
209
210 // FIXME: check other cases.
211 if (RS->isAllocated())
212 state = state->set<RegionState>(Sym, RefState::getEscaped(S));
213
Ted Kremenek19d67b52009-11-23 22:22:01 +0000214 C.addTransition(state);
Zhongxing Xu4985e3e2009-11-17 08:58:18 +0000215}