blob: f514f7ce1aa420d2ab47fbddde078459b4cdd1c9 [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 Xu589c0f22009-11-12 08:38:56 +000055 IdentifierInfo *II_malloc;
56 IdentifierInfo *II_free;
57
58public:
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +000059 MallocChecker() : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(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);
67 void FreeMem(CheckerContext &C, const CallExpr *CE);
68};
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000069} // end anonymous namespace
Zhongxing Xu589c0f22009-11-12 08:38:56 +000070
Zhongxing Xu589c0f22009-11-12 08:38:56 +000071namespace clang {
Zhongxing Xu243fde92009-11-17 07:54:15 +000072 template <>
Zhongxing Xu589c0f22009-11-12 08:38:56 +000073 struct GRStateTrait<RegionState>
74 : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > {
75 static void *GDMIndex() { return MallocChecker::getTag(); }
76 };
77}
78
Zhongxing Xu7b760962009-11-13 07:25:27 +000079void clang::RegisterMallocChecker(GRExprEngine &Eng) {
80 Eng.registerCheck(new MallocChecker());
81}
82
Zhongxing Xu589c0f22009-11-12 08:38:56 +000083void *MallocChecker::getTag() {
84 static int x;
85 return &x;
86}
87
Zhongxing Xua49c6b72009-12-11 03:09:01 +000088bool MallocChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
89 const GRState *state = C.getState();
90 const Expr *Callee = CE->getCallee();
91 SVal L = state->getSVal(Callee);
92
93 const FunctionDecl *FD = L.getAsFunctionDecl();
Zhongxing Xu589c0f22009-11-12 08:38:56 +000094 if (!FD)
Zhongxing Xua49c6b72009-12-11 03:09:01 +000095 return false;
Zhongxing Xu589c0f22009-11-12 08:38:56 +000096
97 ASTContext &Ctx = C.getASTContext();
98 if (!II_malloc)
99 II_malloc = &Ctx.Idents.get("malloc");
100 if (!II_free)
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000101 II_free = &Ctx.Idents.get("free");
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000102
103 if (FD->getIdentifier() == II_malloc) {
104 MallocMem(C, CE);
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000105 return true;
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000106 }
107
108 if (FD->getIdentifier() == II_free) {
109 FreeMem(C, CE);
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000110 return true;
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000111 }
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000112
113 return false;
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000114}
115
116void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000117 unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
118 ValueManager &ValMgr = C.getValueManager();
119
120 SVal RetVal = ValMgr.getConjuredSymbolVal(NULL, CE, CE->getType(), Count);
121
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000122 const GRState *state = C.getState();
Zhongxing Xua49c6b72009-12-11 03:09:01 +0000123 state = state->BindExpr(CE, RetVal);
124
125 SymbolRef Sym = RetVal.getAsLocSymbol();
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000126 assert(Sym);
127 // Set the symbol's state to Allocated.
Ted Kremenek19d67b52009-11-23 22:22:01 +0000128 C.addTransition(state->set<RegionState>(Sym, RefState::getAllocated(CE)));
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000129}
130
131void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
132 const GRState *state = C.getState();
133 SVal ArgVal = state->getSVal(CE->getArg(0));
134 SymbolRef Sym = ArgVal.getAsLocSymbol();
135 assert(Sym);
136
137 const RefState *RS = state->get<RegionState>(Sym);
138 assert(RS);
139
140 // Check double free.
Zhongxing Xu243fde92009-11-17 07:54:15 +0000141 if (RS->isReleased()) {
Ted Kremenek19d67b52009-11-23 22:22:01 +0000142 ExplodedNode *N = C.GenerateSink();
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000143 if (N) {
144 if (!BT_DoubleFree)
145 BT_DoubleFree = new BuiltinBug("Double free",
146 "Try to free a memory block that has been released");
147 // FIXME: should find where it's freed last time.
148 BugReport *R = new BugReport(*BT_DoubleFree,
Benjamin Kramerd02e2322009-11-14 12:08:24 +0000149 BT_DoubleFree->getDescription(), N);
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000150 C.EmitReport(R);
151 }
152 return;
153 }
154
155 // Normal free.
Zhongxing Xu243fde92009-11-17 07:54:15 +0000156 const GRState *FreedState
157 = state->set<RegionState>(Sym, RefState::getReleased(CE));
Ted Kremenek19d67b52009-11-23 22:22:01 +0000158 C.addTransition(FreedState);
Zhongxing Xu589c0f22009-11-12 08:38:56 +0000159}
Zhongxing Xu7b760962009-11-13 07:25:27 +0000160
161void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
162 SymbolReaper &SymReaper) {
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000163 for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
164 E = SymReaper.dead_end(); I != E; ++I) {
165 SymbolRef Sym = *I;
166 const GRState *state = C.getState();
167 const RefState *RS = state->get<RegionState>(Sym);
168 if (!RS)
169 return;
170
Zhongxing Xu243fde92009-11-17 07:54:15 +0000171 if (RS->isAllocated()) {
Ted Kremenek19d67b52009-11-23 22:22:01 +0000172 ExplodedNode *N = C.GenerateSink();
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000173 if (N) {
174 if (!BT_Leak)
175 BT_Leak = new BuiltinBug("Memory leak",
176 "Allocated memory never released. Potential memory leak.");
177 // FIXME: where it is allocated.
Zhongxing Xu243fde92009-11-17 07:54:15 +0000178 BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000179 C.EmitReport(R);
180 }
181 }
182 }
Zhongxing Xu7b760962009-11-13 07:25:27 +0000183}
Zhongxing Xu243fde92009-11-17 07:54:15 +0000184
185void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
186 GRExprEngine &Eng) {
Zhongxing Xuf605aae2009-11-22 13:22:34 +0000187 SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
Zhongxing Xu243fde92009-11-17 07:54:15 +0000188 const GRState *state = B.getState();
189 typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap;
190 SymMap M = state->get<RegionState>();
191
192 for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
193 RefState RS = I->second;
194 if (RS.isAllocated()) {
195 ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
196 if (N) {
197 if (!BT_Leak)
198 BT_Leak = new BuiltinBug("Memory leak",
199 "Allocated memory never released. Potential memory leak.");
200 BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
201 Eng.getBugReporter().EmitReport(R);
202 }
203 }
204 }
205}
Zhongxing Xu4985e3e2009-11-17 08:58:18 +0000206
207void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
208 const Expr *RetE = S->getRetValue();
209 if (!RetE)
210 return;
211
212 const GRState *state = C.getState();
213
214 SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
215
216 if (!Sym)
217 return;
218
219 const RefState *RS = state->get<RegionState>(Sym);
220 if (!RS)
221 return;
222
223 // FIXME: check other cases.
224 if (RS->isAllocated())
225 state = state->set<RegionState>(Sym, RefState::getEscaped(S));
226
Ted Kremenek19d67b52009-11-23 22:22:01 +0000227 C.addTransition(state);
Zhongxing Xu4985e3e2009-11-17 08:58:18 +0000228}