blob: f007aa65da1b1dd1be933837a731d36e647bd85c [file] [log] [blame]
Zhongxing Xu88cca6b2009-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 Xuc4902a52009-11-13 07:25:27 +000015#include "GRExprEngineExperimentalChecks.h"
Zhongxing Xu88cca6b2009-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 Kramer1eb85692009-11-12 12:30:05 +000031class VISIBILITY_HIDDEN MallocChecker : public CheckerVisitor<MallocChecker> {
Zhongxing Xu88cca6b2009-11-12 08:38:56 +000032 BuiltinBug *BT_DoubleFree;
33 IdentifierInfo *II_malloc;
34 IdentifierInfo *II_free;
35
36public:
Zhongxing Xuc4902a52009-11-13 07:25:27 +000037 MallocChecker() : BT_DoubleFree(0) {}
Zhongxing Xu88cca6b2009-11-12 08:38:56 +000038 static void *getTag();
39 void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
Zhongxing Xuc4902a52009-11-13 07:25:27 +000040 void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
41private:
Zhongxing Xu88cca6b2009-11-12 08:38:56 +000042 void MallocMem(CheckerContext &C, const CallExpr *CE);
43 void FreeMem(CheckerContext &C, const CallExpr *CE);
44};
45}
46
47namespace llvm {
48 template<> struct FoldingSetTrait<RefState> {
49 static void Profile(const RefState &X, FoldingSetNodeID &ID) {
50 ID.AddInteger(X);
51 }
52 static void Profile(RefState &X, FoldingSetNodeID &ID) {
53 ID.AddInteger(X);
54 }
55 };
56}
57
58namespace clang {
59 template<>
60 struct GRStateTrait<RegionState>
61 : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > {
62 static void *GDMIndex() { return MallocChecker::getTag(); }
63 };
64}
65
Zhongxing Xuc4902a52009-11-13 07:25:27 +000066void clang::RegisterMallocChecker(GRExprEngine &Eng) {
67 Eng.registerCheck(new MallocChecker());
68}
69
Zhongxing Xu88cca6b2009-11-12 08:38:56 +000070void *MallocChecker::getTag() {
71 static int x;
72 return &x;
73}
74
75void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
76 const FunctionDecl *FD = CE->getDirectCallee();
77 if (!FD)
78 return;
79
80 ASTContext &Ctx = C.getASTContext();
81 if (!II_malloc)
82 II_malloc = &Ctx.Idents.get("malloc");
83 if (!II_free)
84 II_malloc = &Ctx.Idents.get("free");
85
86 if (FD->getIdentifier() == II_malloc) {
87 MallocMem(C, CE);
88 return;
89 }
90
91 if (FD->getIdentifier() == II_free) {
92 FreeMem(C, CE);
93 return;
94 }
95}
96
97void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
98 const GRState *state = C.getState();
99 SVal CallVal = state->getSVal(CE);
100 SymbolRef Sym = CallVal.getAsLocSymbol();
101 assert(Sym);
102 // Set the symbol's state to Allocated.
103 const GRState *AllocState = state->set<RegionState>(Sym, Allocated);
104 C.addTransition(C.GenerateNode(CE, AllocState));
105}
106
107void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
108 const GRState *state = C.getState();
109 SVal ArgVal = state->getSVal(CE->getArg(0));
110 SymbolRef Sym = ArgVal.getAsLocSymbol();
111 assert(Sym);
112
113 const RefState *RS = state->get<RegionState>(Sym);
114 assert(RS);
115
116 // Check double free.
117 if (*RS == Released) {
118 ExplodedNode *N = C.GenerateNode(CE, true);
119 if (N) {
120 if (!BT_DoubleFree)
121 BT_DoubleFree = new BuiltinBug("Double free",
122 "Try to free a memory block that has been released");
123 // FIXME: should find where it's freed last time.
124 BugReport *R = new BugReport(*BT_DoubleFree,
125 BT_DoubleFree->getDescription().c_str(), N);
126 C.EmitReport(R);
127 }
128 return;
129 }
130
131 // Normal free.
132 const GRState *FreedState = state->set<RegionState>(Sym, Released);
133 C.addTransition(C.GenerateNode(CE, FreedState));
134}
Zhongxing Xuc4902a52009-11-13 07:25:27 +0000135
136void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
137 SymbolReaper &SymReaper) {
138}