blob: 6655194d5e9285b8de5ed40899acae0547ab21d2 [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
25enum RefState {
26 Allocated, Released, Escaped
27};
28
29class VISIBILITY_HIDDEN RegionState {};
30
Benjamin Kramer221089b2009-11-12 12:30:05 +000031class VISIBILITY_HIDDEN MallocChecker : public CheckerVisitor<MallocChecker> {
Zhongxing Xu589c0f22009-11-12 08:38:56 +000032 BuiltinBug *BT_DoubleFree;
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +000033 BuiltinBug *BT_Leak;
Zhongxing Xu589c0f22009-11-12 08:38:56 +000034 IdentifierInfo *II_malloc;
35 IdentifierInfo *II_free;
36
37public:
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +000038 MallocChecker() : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0) {}
Zhongxing Xu589c0f22009-11-12 08:38:56 +000039 static void *getTag();
40 void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu7b760962009-11-13 07:25:27 +000041 void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
42private:
Zhongxing Xu589c0f22009-11-12 08:38:56 +000043 void MallocMem(CheckerContext &C, const CallExpr *CE);
44 void FreeMem(CheckerContext &C, const CallExpr *CE);
45};
46}
47
48namespace llvm {
49 template<> struct FoldingSetTrait<RefState> {
50 static void Profile(const RefState &X, FoldingSetNodeID &ID) {
51 ID.AddInteger(X);
52 }
53 static void Profile(RefState &X, FoldingSetNodeID &ID) {
54 ID.AddInteger(X);
55 }
56 };
57}
58
59namespace clang {
60 template<>
61 struct GRStateTrait<RegionState>
62 : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > {
63 static void *GDMIndex() { return MallocChecker::getTag(); }
64 };
65}
66
Zhongxing Xu7b760962009-11-13 07:25:27 +000067void clang::RegisterMallocChecker(GRExprEngine &Eng) {
68 Eng.registerCheck(new MallocChecker());
69}
70
Zhongxing Xu589c0f22009-11-12 08:38:56 +000071void *MallocChecker::getTag() {
72 static int x;
73 return &x;
74}
75
76void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
77 const FunctionDecl *FD = CE->getDirectCallee();
78 if (!FD)
79 return;
80
81 ASTContext &Ctx = C.getASTContext();
82 if (!II_malloc)
83 II_malloc = &Ctx.Idents.get("malloc");
84 if (!II_free)
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +000085 II_free = &Ctx.Idents.get("free");
Zhongxing Xu589c0f22009-11-12 08:38:56 +000086
87 if (FD->getIdentifier() == II_malloc) {
88 MallocMem(C, CE);
89 return;
90 }
91
92 if (FD->getIdentifier() == II_free) {
93 FreeMem(C, CE);
94 return;
95 }
96}
97
98void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
99 const GRState *state = C.getState();
100 SVal CallVal = state->getSVal(CE);
101 SymbolRef Sym = CallVal.getAsLocSymbol();
102 assert(Sym);
103 // Set the symbol's state to Allocated.
104 const GRState *AllocState = state->set<RegionState>(Sym, Allocated);
105 C.addTransition(C.GenerateNode(CE, AllocState));
106}
107
108void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
109 const GRState *state = C.getState();
110 SVal ArgVal = state->getSVal(CE->getArg(0));
111 SymbolRef Sym = ArgVal.getAsLocSymbol();
112 assert(Sym);
113
114 const RefState *RS = state->get<RegionState>(Sym);
115 assert(RS);
116
117 // Check double free.
118 if (*RS == Released) {
119 ExplodedNode *N = C.GenerateNode(CE, true);
120 if (N) {
121 if (!BT_DoubleFree)
122 BT_DoubleFree = new BuiltinBug("Double free",
123 "Try to free a memory block that has been released");
124 // FIXME: should find where it's freed last time.
125 BugReport *R = new BugReport(*BT_DoubleFree,
126 BT_DoubleFree->getDescription().c_str(), N);
127 C.EmitReport(R);
128 }
129 return;
130 }
131
132 // Normal free.
133 const GRState *FreedState = state->set<RegionState>(Sym, Released);
134 C.addTransition(C.GenerateNode(CE, FreedState));
135}
Zhongxing Xu7b760962009-11-13 07:25:27 +0000136
137void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
138 SymbolReaper &SymReaper) {
Zhongxing Xufc7ac8f2009-11-13 07:48:11 +0000139 for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
140 E = SymReaper.dead_end(); I != E; ++I) {
141 SymbolRef Sym = *I;
142 const GRState *state = C.getState();
143 const RefState *RS = state->get<RegionState>(Sym);
144 if (!RS)
145 return;
146
147 if (*RS == Allocated) {
148 ExplodedNode *N = C.GenerateNode(S, true);
149 if (N) {
150 if (!BT_Leak)
151 BT_Leak = new BuiltinBug("Memory leak",
152 "Allocated memory never released. Potential memory leak.");
153 // FIXME: where it is allocated.
154 BugReport *R = new BugReport(*BT_Leak,
155 BT_Leak->getDescription().c_str(), N);
156 C.EmitReport(R);
157 }
158 }
159 }
Zhongxing Xu7b760962009-11-13 07:25:27 +0000160}