blob: a775bcddf09a30dbc453d6ad6672804287ecfd85 [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
15#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
16#include "clang/Analysis/PathSensitive/GRState.h"
17#include "clang/Analysis/PathSensitive/GRStateTrait.h"
18#include "clang/Analysis/PathSensitive/SymbolManager.h"
19#include "llvm/ADT/ImmutableMap.h"
20using namespace clang;
21
22namespace {
23
24enum RefState {
25 Allocated, Released, Escaped
26};
27
28class VISIBILITY_HIDDEN RegionState {};
29
30class VISIBILITY_HIDDEN MallocChecker : CheckerVisitor<MallocChecker> {
31 BuiltinBug *BT_DoubleFree;
32 IdentifierInfo *II_malloc;
33 IdentifierInfo *II_free;
34
35public:
36 static void *getTag();
37 void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
38 void MallocMem(CheckerContext &C, const CallExpr *CE);
39 void FreeMem(CheckerContext &C, const CallExpr *CE);
40};
41}
42
43namespace llvm {
44 template<> struct FoldingSetTrait<RefState> {
45 static void Profile(const RefState &X, FoldingSetNodeID &ID) {
46 ID.AddInteger(X);
47 }
48 static void Profile(RefState &X, FoldingSetNodeID &ID) {
49 ID.AddInteger(X);
50 }
51 };
52}
53
54namespace clang {
55 template<>
56 struct GRStateTrait<RegionState>
57 : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > {
58 static void *GDMIndex() { return MallocChecker::getTag(); }
59 };
60}
61
62void *MallocChecker::getTag() {
63 static int x;
64 return &x;
65}
66
67void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
68 const FunctionDecl *FD = CE->getDirectCallee();
69 if (!FD)
70 return;
71
72 ASTContext &Ctx = C.getASTContext();
73 if (!II_malloc)
74 II_malloc = &Ctx.Idents.get("malloc");
75 if (!II_free)
76 II_malloc = &Ctx.Idents.get("free");
77
78 if (FD->getIdentifier() == II_malloc) {
79 MallocMem(C, CE);
80 return;
81 }
82
83 if (FD->getIdentifier() == II_free) {
84 FreeMem(C, CE);
85 return;
86 }
87}
88
89void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
90 const GRState *state = C.getState();
91 SVal CallVal = state->getSVal(CE);
92 SymbolRef Sym = CallVal.getAsLocSymbol();
93 assert(Sym);
94 // Set the symbol's state to Allocated.
95 const GRState *AllocState = state->set<RegionState>(Sym, Allocated);
96 C.addTransition(C.GenerateNode(CE, AllocState));
97}
98
99void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
100 const GRState *state = C.getState();
101 SVal ArgVal = state->getSVal(CE->getArg(0));
102 SymbolRef Sym = ArgVal.getAsLocSymbol();
103 assert(Sym);
104
105 const RefState *RS = state->get<RegionState>(Sym);
106 assert(RS);
107
108 // Check double free.
109 if (*RS == Released) {
110 ExplodedNode *N = C.GenerateNode(CE, true);
111 if (N) {
112 if (!BT_DoubleFree)
113 BT_DoubleFree = new BuiltinBug("Double free",
114 "Try to free a memory block that has been released");
115 // FIXME: should find where it's freed last time.
116 BugReport *R = new BugReport(*BT_DoubleFree,
117 BT_DoubleFree->getDescription().c_str(), N);
118 C.EmitReport(R);
119 }
120 return;
121 }
122
123 // Normal free.
124 const GRState *FreedState = state->set<RegionState>(Sym, Released);
125 C.addTransition(C.GenerateNode(CE, FreedState));
126}