aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/MallocChecker.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2010-01-25 04:41:41 +0000
committerTed Kremenek <kremenek@apple.com>2010-01-25 04:41:41 +0000
commit1309f9a3b225ea846e5822691c39a77423125505 (patch)
tree1ba6d1976da4f426292619af026dbf9d9314c573 /lib/Analysis/MallocChecker.cpp
parent3db9eb1fbe5771d3d64db01af46b4eee9aca8ed0 (diff)
Split libAnalysis into two libraries: libAnalysis and libChecker.
(1) libAnalysis is a generic analysis library that can be used by Sema. It defines the CFG, basic dataflow analysis primitives, and inexpensive flow-sensitive analyses (e.g. LiveVariables). (2) libChecker contains the guts of the static analyzer, incuding the path-sensitive analysis engine and domain-specific checks. Now any clients that want to use the frontend to build their own tools don't need to link in the entire static analyzer. This change exposes various obvious cleanups that can be made to the layout of files and headers in libChecker. More changes pending. :) This change also exposed a layering violation between AnalysisContext and MemRegion. BlockInvocationContext shouldn't explicitly know about BlockDataRegions. For now I've removed the BlockDataRegion* from BlockInvocationContext (removing context-sensitivity; although this wasn't used yet). We need to have a better way to extend BlockInvocationContext (and any LocationContext) to add context-sensitivty. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94406 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/MallocChecker.cpp')
-rw-r--r--lib/Analysis/MallocChecker.cpp336
1 files changed, 0 insertions, 336 deletions
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp
deleted file mode 100644
index 28f4db7880..0000000000
--- a/lib/Analysis/MallocChecker.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-//=== 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 "GRExprEngineExperimentalChecks.h"
-#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 {
-
-class RefState {
- enum Kind { AllocateUnchecked, AllocateFailed, Released, Escaped } K;
- const Stmt *S;
-
-public:
- RefState(Kind k, const Stmt *s) : K(k), S(s) {}
-
- bool isAllocated() const { return K == AllocateUnchecked; }
- bool isReleased() const { return K == Released; }
- bool isEscaped() const { return K == Escaped; }
-
- bool operator==(const RefState &X) const {
- return K == X.K && S == X.S;
- }
-
- static RefState getAllocateUnchecked(const Stmt *s) {
- return RefState(AllocateUnchecked, s);
- }
- static RefState getAllocateFailed() {
- return RefState(AllocateFailed, 0);
- }
- static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
- static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(K);
- ID.AddPointer(S);
- }
-};
-
-class RegionState {};
-
-class MallocChecker : public CheckerVisitor<MallocChecker> {
- BuiltinBug *BT_DoubleFree;
- BuiltinBug *BT_Leak;
- IdentifierInfo *II_malloc, *II_free, *II_realloc;
-
-public:
- MallocChecker()
- : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0), II_realloc(0) {}
- static void *getTag();
- bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
- void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
- void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
- const GRState *EvalAssume(const GRState *state, SVal Cond, bool Assumption);
-
-private:
- void MallocMem(CheckerContext &C, const CallExpr *CE);
- const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
- const Expr *SizeEx, const GRState *state);
- void FreeMem(CheckerContext &C, const CallExpr *CE);
- const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
- const GRState *state);
-
- void ReallocMem(CheckerContext &C, const CallExpr *CE);
-};
-} // end anonymous namespace
-
-typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy;
-
-namespace clang {
- template <>
- struct GRStateTrait<RegionState>
- : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > {
- static void *GDMIndex() { return MallocChecker::getTag(); }
- };
-}
-
-void clang::RegisterMallocChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new MallocChecker());
-}
-
-void *MallocChecker::getTag() {
- static int x;
- return &x;
-}
-
-bool MallocChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
-
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
-
- ASTContext &Ctx = C.getASTContext();
- if (!II_malloc)
- II_malloc = &Ctx.Idents.get("malloc");
- if (!II_free)
- II_free = &Ctx.Idents.get("free");
- if (!II_realloc)
- II_realloc = &Ctx.Idents.get("realloc");
-
- if (FD->getIdentifier() == II_malloc) {
- MallocMem(C, CE);
- return true;
- }
-
- if (FD->getIdentifier() == II_free) {
- FreeMem(C, CE);
- return true;
- }
-
- if (FD->getIdentifier() == II_realloc) {
- ReallocMem(C, CE);
- return true;
- }
-
- return false;
-}
-
-void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = MallocMemAux(C, CE, CE->getArg(0), C.getState());
- C.addTransition(state);
-}
-
-const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
- const CallExpr *CE,
- const Expr *SizeEx,
- const GRState *state) {
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
- ValueManager &ValMgr = C.getValueManager();
-
- SVal RetVal = ValMgr.getConjuredSymbolVal(NULL, CE, CE->getType(), Count);
-
- SVal Size = state->getSVal(SizeEx);
-
- state = C.getEngine().getStoreManager().setExtent(state, RetVal.getAsRegion(),
- Size);
-
- state = state->BindExpr(CE, RetVal);
-
- SymbolRef Sym = RetVal.getAsLocSymbol();
- assert(Sym);
- // Set the symbol's state to Allocated.
- return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE));
-}
-
-void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = FreeMemAux(C, CE, C.getState());
-
- if (state)
- C.addTransition(state);
-}
-
-const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
- const GRState *state) {
- SVal ArgVal = state->getSVal(CE->getArg(0));
- SymbolRef Sym = ArgVal.getAsLocSymbol();
- assert(Sym);
-
- const RefState *RS = state->get<RegionState>(Sym);
-
- // If the symbol has not been tracked, return. This is possible when free() is
- // called on a pointer that does not get its pointee directly from malloc().
- // Full support of this requires inter-procedural analysis.
- if (!RS)
- return state;
-
- // Check double free.
- if (RS->isReleased()) {
- ExplodedNode *N = C.GenerateSink();
- 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(), N);
- C.EmitReport(R);
- }
- return NULL;
- }
-
- // Normal free.
- return state->set<RegionState>(Sym, RefState::getReleased(CE));
-}
-
-void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- const Expr *Arg0 = CE->getArg(0);
- DefinedOrUnknownSVal Arg0Val=cast<DefinedOrUnknownSVal>(state->getSVal(Arg0));
-
- ValueManager &ValMgr = C.getValueManager();
- SValuator &SVator = C.getSValuator();
-
- DefinedOrUnknownSVal PtrEQ = SVator.EvalEQ(state, Arg0Val, ValMgr.makeNull());
-
- // If the ptr is NULL, the call is equivalent to malloc(size).
- if (const GRState *stateEqual = state->Assume(PtrEQ, true)) {
- // Hack: set the NULL symbolic region to released to suppress false warning.
- // In the future we should add more states for allocated regions, e.g.,
- // CheckedNull, CheckedNonNull.
-
- SymbolRef Sym = Arg0Val.getAsLocSymbol();
- if (Sym)
- stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE));
-
- const GRState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1), stateEqual);
- C.addTransition(stateMalloc);
- }
-
- if (const GRState *stateNotEqual = state->Assume(PtrEQ, false)) {
- const Expr *Arg1 = CE->getArg(1);
- DefinedOrUnknownSVal Arg1Val =
- cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1));
- DefinedOrUnknownSVal SizeZero = SVator.EvalEQ(stateNotEqual, Arg1Val,
- ValMgr.makeIntValWithPtrWidth(0, false));
-
- if (const GRState *stateSizeZero = stateNotEqual->Assume(SizeZero, true)) {
- const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero);
- if (stateFree)
- C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
- }
-
- if (const GRState *stateSizeNotZero=stateNotEqual->Assume(SizeZero,false)) {
- const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero);
- if (stateFree) {
- // FIXME: We should copy the content of the original buffer.
- const GRState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
- stateFree);
- C.addTransition(stateRealloc);
- }
- }
- }
-}
-
-void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
- SymbolReaper &SymReaper) {
- for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
- E = SymReaper.dead_end(); I != E; ++I) {
- SymbolRef Sym = *I;
- const GRState *state = C.getState();
- const RefState *RS = state->get<RegionState>(Sym);
- if (!RS)
- return;
-
- if (RS->isAllocated()) {
- ExplodedNode *N = C.GenerateSink();
- if (N) {
- if (!BT_Leak)
- BT_Leak = new BuiltinBug("Memory leak",
- "Allocated memory never released. Potential memory leak.");
- // FIXME: where it is allocated.
- BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
- C.EmitReport(R);
- }
- }
- }
-}
-
-void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
- GRExprEngine &Eng) {
- SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
- const GRState *state = B.getState();
- typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap;
- SymMap M = state->get<RegionState>();
-
- for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
- RefState RS = I->second;
- if (RS.isAllocated()) {
- ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
- if (N) {
- if (!BT_Leak)
- BT_Leak = new BuiltinBug("Memory leak",
- "Allocated memory never released. Potential memory leak.");
- BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
- Eng.getBugReporter().EmitReport(R);
- }
- }
- }
-}
-
-void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
- const Expr *RetE = S->getRetValue();
- if (!RetE)
- return;
-
- const GRState *state = C.getState();
-
- SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
-
- if (!Sym)
- return;
-
- const RefState *RS = state->get<RegionState>(Sym);
- if (!RS)
- return;
-
- // FIXME: check other cases.
- if (RS->isAllocated())
- state = state->set<RegionState>(Sym, RefState::getEscaped(S));
-
- C.addTransition(state);
-}
-
-const GRState *MallocChecker::EvalAssume(const GRState *state, SVal Cond,
- bool Assumption) {
- // If a symblic region is assumed to NULL, set its state to AllocateFailed.
- // FIXME: should also check symbols assumed to non-null.
-
- RegionStateTy RS = state->get<RegionState>();
-
- for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
- if (state->getSymVal(I.getKey()))
- state = state->set<RegionState>(I.getKey(),RefState::getAllocateFailed());
- }
-
- return state;
-}