blob: 2ed070a170cd992ec1e5a61336e9b4e51e30414a [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 Xu7fb14642009-12-11 00:55:44 +000025class RefState {
Zhongxing Xu243fde92009-11-17 07:54:15 +000026 enum Kind { Allocated, Released, Escaped } K;
27 const Stmt *S;
28
Zhongxing Xu7fb14642009-12-11 00:55:44 +000029public:
Zhongxing Xu243fde92009-11-17 07:54:15 +000030 RefState(Kind k, const Stmt *s) : K(k), S(s) {}
31
32 bool isAllocated() const { return K == Allocated; }
33 bool isReleased() const { return K == Released; }
34 bool isEscaped() const { return K == Escaped; }
35
36 bool operator==(const RefState &X) const {
37 return K == X.K && S == X.S;
38 }
39
40 static RefState getAllocated(const Stmt *s) { return RefState(Allocated, s); }
41 static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
42 static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); }
43
44 void Profile(llvm::FoldingSetNodeID &ID) const {
45 ID.AddInteger(K);
46 ID.AddPointer(S);
47 }
Zhongxing Xu589c0f22009-11-12 08:38:56 +000048};
49
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000050class RegionState {};
Zhongxing Xu589c0f22009-11-12 08:38:56 +000051
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000052class MallocChecker : public CheckerVisitor<MallocChecker> {
Zhongxing Xu589c0f22009-11-12 08:38:56 +000053 BuiltinBug *BT_DoubleFree;
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +000054 BuiltinBug *BT_Leak;
Zhongxing Xud9c84c82009-12-12 12:29:38 +000055 IdentifierInfo *II_malloc, *II_free, *II_realloc;
Zhongxing Xu589c0f22009-11-12 08:38:56 +000056
57public:
Zhongxing Xud9c84c82009-12-12 12:29:38 +000058 MallocChecker()
59 : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0), II_realloc(0) {}
Zhongxing Xu589c0f22009-11-12 08:38:56 +000060 static void *getTag();
Zhongxing Xua49c6b72009-12-11 03:09:01 +000061 bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu7b760962009-11-13 07:25:27 +000062 void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
Zhongxing Xu243fde92009-11-17 07:54:15 +000063 void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
Zhongxing Xu4985e3e2009-11-17 08:58:18 +000064 void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
Zhongxing Xu7b760962009-11-13 07:25:27 +000065private:
Zhongxing Xu589c0f22009-11-12 08:38:56 +000066 void MallocMem(CheckerContext &C, const CallExpr *CE);
Zhongxing Xud9c84c82009-12-12 12:29:38 +000067 const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
68 const GRState *state);
Zhongxing Xu589c0f22009-11-12 08:38:56 +000069 void FreeMem(CheckerContext &C, const CallExpr *CE);
Zhongxing Xud9c84c82009-12-12 12:29:38 +000070 const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
71 const GRState *state);
72
73 void ReallocMem(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu589c0f22009-11-12 08:38:56 +000074};
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000075} // end anonymous namespace
Zhongxing Xu589c0f22009-11-12 08:38:56 +000076
Zhongxing Xu589c0f22009-11-12 08:38:56 +000077namespace clang {
Zhongxing Xu243fde92009-11-17 07:54:15 +000078 template <>
Zhongxing Xu589c0f22009-11-12 08:38:56 +000079 struct GRStateTrait<RegionState>
80 : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > {
81 static void *GDMIndex() { return MallocChecker::getTag(); }
82 };
83}
84
Zhongxing Xu7b760962009-11-13 07:25:27 +000085void clang::RegisterMallocChecker(GRExprEngine &Eng) {
86 Eng.registerCheck(new MallocChecker());
87}
88
Zhongxing Xu589c0f22009-11-12 08:38:56 +000089void *MallocChecker::getTag() {
90 static int x;
91 return &x;
92}
93
Zhongxing Xua49c6b72009-12-11 03:09:01 +000094bool MallocChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
95 const GRState *state = C.getState();
96 const Expr *Callee = CE->getCallee();
97 SVal L = state->getSVal(Callee);
98
99 const FunctionDecl *FD = L.getAsFunctionDecl();
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000100 if (!FD)
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000101 return false;
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000102
103 ASTContext &Ctx = C.getASTContext();
104 if (!II_malloc)
105 II_malloc = &Ctx.Idents.get("malloc");
106 if (!II_free)
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000107 II_free = &Ctx.Idents.get("free");
Zhongxing Xud9c84c82009-12-12 12:29:38 +0000108 if (!II_realloc)
109 II_realloc = &Ctx.Idents.get("realloc");
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000110
111 if (FD->getIdentifier() == II_malloc) {
112 MallocMem(C, CE);
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000113 return true;
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000114 }
115
116 if (FD->getIdentifier() == II_free) {
117 FreeMem(C, CE);
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000118 return true;
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000119 }
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000120
Zhongxing Xud9c84c82009-12-12 12:29:38 +0000121 if (FD->getIdentifier() == II_realloc) {
122 ReallocMem(C, CE);
123 return true;
124 }
125
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000126 return false;
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000127}
128
129void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xud9c84c82009-12-12 12:29:38 +0000130 const GRState *state = MallocMemAux(C, CE, C.getState());
131 C.addTransition(state);
132}
133
134const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
135 const CallExpr *CE,
136 const GRState *state) {
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000137 unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
138 ValueManager &ValMgr = C.getValueManager();
139
140 SVal RetVal = ValMgr.getConjuredSymbolVal(NULL, CE, CE->getType(), Count);
141
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000142 state = state->BindExpr(CE, RetVal);
143
144 SymbolRef Sym = RetVal.getAsLocSymbol();
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000145 assert(Sym);
146 // Set the symbol's state to Allocated.
Zhongxing Xud9c84c82009-12-12 12:29:38 +0000147 return state->set<RegionState>(Sym, RefState::getAllocated(CE));
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000148}
149
150void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xud9c84c82009-12-12 12:29:38 +0000151 const GRState *state = FreeMemAux(C, CE, C.getState());
152
153 if (state)
154 C.addTransition(state);
155}
156
157const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
158 const GRState *state) {
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000159 SVal ArgVal = state->getSVal(CE->getArg(0));
160 SymbolRef Sym = ArgVal.getAsLocSymbol();
161 assert(Sym);
162
163 const RefState *RS = state->get<RegionState>(Sym);
164 assert(RS);
165
166 // Check double free.
Zhongxing Xu243fde92009-11-17 07:54:15 +0000167 if (RS->isReleased()) {
Ted Kremenek19d67b52009-11-23 22:22:01 +0000168 ExplodedNode *N = C.GenerateSink();
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000169 if (N) {
170 if (!BT_DoubleFree)
171 BT_DoubleFree = new BuiltinBug("Double free",
172 "Try to free a memory block that has been released");
173 // FIXME: should find where it's freed last time.
174 BugReport *R = new BugReport(*BT_DoubleFree,
Benjamin Kramerd02e2322009-11-14 12:08:24 +0000175 BT_DoubleFree->getDescription(), N);
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000176 C.EmitReport(R);
177 }
Zhongxing Xud9c84c82009-12-12 12:29:38 +0000178 return NULL;
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000179 }
180
181 // Normal free.
Zhongxing Xud9c84c82009-12-12 12:29:38 +0000182 return state->set<RegionState>(Sym, RefState::getReleased(CE));
183}
184
185void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
186 const GRState *state = C.getState();
187 const Expr *Arg0 = CE->getArg(0);
188 DefinedOrUnknownSVal Arg0Val=cast<DefinedOrUnknownSVal>(state->getSVal(Arg0));
189
190 ValueManager &ValMgr = C.getValueManager();
191 SValuator &SVator = C.getSValuator();
192
193 DefinedOrUnknownSVal PtrEQ = SVator.EvalEQ(state, Arg0Val, ValMgr.makeNull());
194
195 // If the ptr is NULL, the call is equivalent to malloc(size).
196 if (const GRState *stateEqual = state->Assume(PtrEQ, true)) {
197 // Hack: set the NULL symbolic region to released to suppress false warning.
198 // In the future we should add more states for allocated regions, e.g.,
199 // CheckedNull, CheckedNonNull.
200
201 SymbolRef Sym = Arg0Val.getAsLocSymbol();
202 if (Sym)
203 stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE));
204
205 const GRState *stateMalloc = MallocMemAux(C, CE, stateEqual);
206 C.addTransition(stateMalloc);
207 }
208
209 if (const GRState *stateNotEqual = state->Assume(PtrEQ, false)) {
210 const Expr *Arg1 = CE->getArg(1);
211 DefinedOrUnknownSVal Arg1Val =
212 cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1));
213 DefinedOrUnknownSVal SizeZero = SVator.EvalEQ(stateNotEqual, Arg1Val,
214 ValMgr.makeIntValWithPtrWidth(0, false));
215
216 if (const GRState *stateSizeZero = stateNotEqual->Assume(SizeZero, true)) {
217 const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero);
218 if (stateFree)
219 C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
220 }
221
222 if (const GRState *stateSizeNotZero=stateNotEqual->Assume(SizeZero,false)) {
223 const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero);
224 if (stateFree) {
225 // FIXME: We should copy the content of the original buffer.
226 const GRState *stateRealloc = MallocMemAux(C, CE, stateFree);
227 C.addTransition(stateRealloc);
228 }
229 }
230 }
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000231}
Zhongxing Xu7b760962009-11-13 07:25:27 +0000232
233void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
234 SymbolReaper &SymReaper) {
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000235 for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
236 E = SymReaper.dead_end(); I != E; ++I) {
237 SymbolRef Sym = *I;
238 const GRState *state = C.getState();
239 const RefState *RS = state->get<RegionState>(Sym);
240 if (!RS)
241 return;
242
Zhongxing Xu243fde92009-11-17 07:54:15 +0000243 if (RS->isAllocated()) {
Ted Kremenek19d67b52009-11-23 22:22:01 +0000244 ExplodedNode *N = C.GenerateSink();
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000245 if (N) {
246 if (!BT_Leak)
247 BT_Leak = new BuiltinBug("Memory leak",
248 "Allocated memory never released. Potential memory leak.");
249 // FIXME: where it is allocated.
Zhongxing Xu243fde92009-11-17 07:54:15 +0000250 BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000251 C.EmitReport(R);
252 }
253 }
254 }
Zhongxing Xu7b760962009-11-13 07:25:27 +0000255}
Zhongxing Xu243fde92009-11-17 07:54:15 +0000256
257void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
258 GRExprEngine &Eng) {
Zhongxing Xuf605aae2009-11-22 13:22:34 +0000259 SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
Zhongxing Xu243fde92009-11-17 07:54:15 +0000260 const GRState *state = B.getState();
261 typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap;
262 SymMap M = state->get<RegionState>();
263
264 for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
265 RefState RS = I->second;
266 if (RS.isAllocated()) {
267 ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
268 if (N) {
269 if (!BT_Leak)
270 BT_Leak = new BuiltinBug("Memory leak",
271 "Allocated memory never released. Potential memory leak.");
272 BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
273 Eng.getBugReporter().EmitReport(R);
274 }
275 }
276 }
277}
Zhongxing Xu4985e3e2009-11-17 08:58:18 +0000278
279void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
280 const Expr *RetE = S->getRetValue();
281 if (!RetE)
282 return;
283
284 const GRState *state = C.getState();
285
286 SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
287
288 if (!Sym)
289 return;
290
291 const RefState *RS = state->get<RegionState>(Sym);
292 if (!RS)
293 return;
294
295 // FIXME: check other cases.
296 if (RS->isAllocated())
297 state = state->set<RegionState>(Sym, RefState::getEscaped(S));
298
Ted Kremenek19d67b52009-11-23 22:22:01 +0000299 C.addTransition(state);
Zhongxing Xu4985e3e2009-11-17 08:58:18 +0000300}