diff options
author | Zhongxing Xu <xuzhongxing@gmail.com> | 2009-11-12 08:38:56 +0000 |
---|---|---|
committer | Zhongxing Xu <xuzhongxing@gmail.com> | 2009-11-12 08:38:56 +0000 |
commit | 589c0f28f8600ab0a2de969988a80c113be9b45d (patch) | |
tree | f0f9d8824c78e7744625e6d181f4f346e5f9fbbd /lib/Analysis/MallocChecker.cpp | |
parent | dcdd2a064a6d3ea7712169629328ef80d6cb28ec (diff) |
Add boilerplate logic for a malloc/free checker.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86978 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/MallocChecker.cpp')
-rw-r--r-- | lib/Analysis/MallocChecker.cpp | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp new file mode 100644 index 0000000000..a775bcddf0 --- /dev/null +++ b/lib/Analysis/MallocChecker.cpp @@ -0,0 +1,126 @@ +//=== MallocChecker.cpp - A malloc/free checker -------------------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines malloc/free checker, which checks for potential memory +// leaks, double free, and use-after-free problems. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/GRStateTrait.h" +#include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "llvm/ADT/ImmutableMap.h" +using namespace clang; + +namespace { + +enum RefState { + Allocated, Released, Escaped +}; + +class VISIBILITY_HIDDEN RegionState {}; + +class VISIBILITY_HIDDEN MallocChecker : CheckerVisitor<MallocChecker> { + BuiltinBug *BT_DoubleFree; + IdentifierInfo *II_malloc; + IdentifierInfo *II_free; + +public: + static void *getTag(); + void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE); + void MallocMem(CheckerContext &C, const CallExpr *CE); + void FreeMem(CheckerContext &C, const CallExpr *CE); +}; +} + +namespace llvm { + template<> struct FoldingSetTrait<RefState> { + static void Profile(const RefState &X, FoldingSetNodeID &ID) { + ID.AddInteger(X); + } + static void Profile(RefState &X, FoldingSetNodeID &ID) { + ID.AddInteger(X); + } + }; +} + +namespace clang { + template<> + struct GRStateTrait<RegionState> + : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > { + static void *GDMIndex() { return MallocChecker::getTag(); } + }; +} + +void *MallocChecker::getTag() { + static int x; + return &x; +} + +void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) { + const FunctionDecl *FD = CE->getDirectCallee(); + if (!FD) + return; + + ASTContext &Ctx = C.getASTContext(); + if (!II_malloc) + II_malloc = &Ctx.Idents.get("malloc"); + if (!II_free) + II_malloc = &Ctx.Idents.get("free"); + + if (FD->getIdentifier() == II_malloc) { + MallocMem(C, CE); + return; + } + + if (FD->getIdentifier() == II_free) { + FreeMem(C, CE); + return; + } +} + +void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + SVal CallVal = state->getSVal(CE); + SymbolRef Sym = CallVal.getAsLocSymbol(); + assert(Sym); + // Set the symbol's state to Allocated. + const GRState *AllocState = state->set<RegionState>(Sym, Allocated); + C.addTransition(C.GenerateNode(CE, AllocState)); +} + +void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + SVal ArgVal = state->getSVal(CE->getArg(0)); + SymbolRef Sym = ArgVal.getAsLocSymbol(); + assert(Sym); + + const RefState *RS = state->get<RegionState>(Sym); + assert(RS); + + // Check double free. + if (*RS == Released) { + ExplodedNode *N = C.GenerateNode(CE, true); + if (N) { + if (!BT_DoubleFree) + BT_DoubleFree = new BuiltinBug("Double free", + "Try to free a memory block that has been released"); + // FIXME: should find where it's freed last time. + BugReport *R = new BugReport(*BT_DoubleFree, + BT_DoubleFree->getDescription().c_str(), N); + C.EmitReport(R); + } + return; + } + + // Normal free. + const GRState *FreedState = state->set<RegionState>(Sym, Released); + C.addTransition(C.GenerateNode(CE, FreedState)); +} |