diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 140 |
1 files changed, 74 insertions, 66 deletions
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 9100215..5631802 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -17,8 +17,8 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/ADT/ImmutableMap.h" using namespace clang; @@ -80,35 +80,37 @@ public: void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const; void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; - const GRState *evalAssume(const GRState *state, SVal Cond, + const ProgramState *evalAssume(const ProgramState *state, SVal Cond, bool Assumption) const; - void checkLocation(SVal l, bool isLoad, CheckerContext &C) const; - void checkBind(SVal location, SVal val, CheckerContext &C) const; + void checkLocation(SVal l, bool isLoad, const Stmt *S, + CheckerContext &C) const; + void checkBind(SVal location, SVal val, const Stmt*S, + CheckerContext &C) const; private: static void MallocMem(CheckerContext &C, const CallExpr *CE); static void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, const OwnershipAttr* Att); - static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, + static const ProgramState *MallocMemAux(CheckerContext &C, const CallExpr *CE, const Expr *SizeEx, SVal Init, - const GRState *state) { + const ProgramState *state) { return MallocMemAux(C, CE, state->getSVal(SizeEx), Init, state); } - static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, + static const ProgramState *MallocMemAux(CheckerContext &C, const CallExpr *CE, SVal SizeEx, SVal Init, - const GRState *state); + const ProgramState *state); void FreeMem(CheckerContext &C, const CallExpr *CE) const; void FreeMemAttr(CheckerContext &C, const CallExpr *CE, const OwnershipAttr* Att) const; - const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE, - const GRState *state, unsigned Num, bool Hold) const; + const ProgramState *FreeMemAux(CheckerContext &C, const CallExpr *CE, + const ProgramState *state, unsigned Num, bool Hold) const; void ReallocMem(CheckerContext &C, const CallExpr *CE) const; static void CallocMem(CheckerContext &C, const CallExpr *CE); - static bool SummarizeValue(llvm::raw_ostream& os, SVal V); - static bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR); + static bool SummarizeValue(raw_ostream &os, SVal V); + static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR); void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const; }; } // end anonymous namespace @@ -118,15 +120,15 @@ typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy; namespace clang { namespace ento { template <> - struct GRStateTrait<RegionState> - : public GRStatePartialTrait<RegionStateTy> { + struct ProgramStateTrait<RegionState> + : public ProgramStatePartialTrait<RegionStateTy> { static void *GDMIndex() { static int x; return &x; } }; } } bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); @@ -193,7 +195,7 @@ bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { } void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { - const GRState *state = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), + const ProgramState *state = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), C.getState()); C.addTransition(state); } @@ -205,21 +207,21 @@ void MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); if (I != E) { - const GRState *state = + const ProgramState *state = MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), C.getState()); C.addTransition(state); return; } - const GRState *state = MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), + const ProgramState *state = MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), C.getState()); C.addTransition(state); } -const GRState *MallocChecker::MallocMemAux(CheckerContext &C, +const ProgramState *MallocChecker::MallocMemAux(CheckerContext &C, const CallExpr *CE, SVal Size, SVal Init, - const GRState *state) { - unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + const ProgramState *state) { + unsigned Count = C.getCurrentBlockCount(); SValBuilder &svalBuilder = C.getSValBuilder(); // Set the return value. @@ -247,7 +249,7 @@ const GRState *MallocChecker::MallocMemAux(CheckerContext &C, } void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = FreeMemAux(C, CE, C.getState(), 0, false); + const ProgramState *state = FreeMemAux(C, CE, C.getState(), 0, false); if (state) C.addTransition(state); @@ -260,15 +262,15 @@ void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE, for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); I != E; ++I) { - const GRState *state = FreeMemAux(C, CE, C.getState(), *I, + const ProgramState *state = FreeMemAux(C, CE, C.getState(), *I, Att->getOwnKind() == OwnershipAttr::Holds); if (state) C.addTransition(state); } } -const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, - const GRState *state, unsigned Num, +const ProgramState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, + const ProgramState *state, unsigned Num, bool Hold) const { const Expr *ArgExpr = CE->getArg(Num); SVal ArgVal = state->getSVal(ArgExpr); @@ -281,7 +283,7 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, // FIXME: Technically using 'Assume' here can result in a path // bifurcation. In such cases we need to return two states, not just one. - const GRState *notNullState, *nullState; + const ProgramState *notNullState, *nullState; llvm::tie(notNullState, nullState) = state->assume(location); // The explicit NULL case, no operation is performed. @@ -364,7 +366,7 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, return notNullState->set<RegionState>(Sym, RefState::getReleased(CE)); } -bool MallocChecker::SummarizeValue(llvm::raw_ostream& os, SVal V) { +bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) { if (nonloc::ConcreteInt *IntVal = dyn_cast<nonloc::ConcreteInt>(&V)) os << "an integer (" << IntVal->getValue() << ")"; else if (loc::ConcreteInt *ConstAddr = dyn_cast<loc::ConcreteInt>(&V)) @@ -377,13 +379,13 @@ bool MallocChecker::SummarizeValue(llvm::raw_ostream& os, SVal V) { return true; } -bool MallocChecker::SummarizeRegion(llvm::raw_ostream& os, +bool MallocChecker::SummarizeRegion(raw_ostream &os, const MemRegion *MR) { switch (MR->getKind()) { case MemRegion::FunctionTextRegionKind: { const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl(); if (FD) - os << "the address of the function '" << FD << "'"; + os << "the address of the function '" << *FD << '\''; else os << "the address of a function"; return true; @@ -484,14 +486,14 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, os << "not memory allocated by malloc()"; } - EnhancedBugReport *R = new EnhancedBugReport(*BT_BadFree, os.str(), N); + BugReport *R = new BugReport(*BT_BadFree, os.str(), N); R->addRange(range); C.EmitReport(R); } } void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); const Expr *arg0Expr = CE->getArg(0); DefinedOrUnknownSVal arg0Val = cast<DefinedOrUnknownSVal>(state->getSVal(arg0Expr)); @@ -517,7 +519,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { // If the ptr is NULL and the size is not 0, the call is equivalent to // malloc(size). - const GRState *stateEqual = state->assume(PtrEQ, true); + const ProgramState *stateEqual = state->assume(PtrEQ, true); if (stateEqual && state->assume(SizeZero, false)) { // 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., @@ -527,28 +529,25 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { if (Sym) stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE)); - const GRState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1), + const ProgramState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), stateEqual); C.addTransition(stateMalloc); } - if (const GRState *stateNotEqual = state->assume(PtrEQ, false)) { + if (const ProgramState *stateNotEqual = state->assume(PtrEQ, false)) { // If the size is 0, free the memory. - if (const GRState *stateSizeZero = stateNotEqual->assume(SizeZero, true)) - if (const GRState *stateFree = + if (const ProgramState *stateSizeZero = stateNotEqual->assume(SizeZero, true)) + if (const ProgramState *stateFree = FreeMemAux(C, CE, stateSizeZero, 0, false)) { - // Add the state transition to set input pointer argument to be free. - C.addTransition(stateFree); - - // Bind the return value to UndefinedVal because it is now free. - C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true)); + // Bind the return value to NULL because it is now free. + C.addTransition(stateFree->BindExpr(CE, svalBuilder.makeNull(), true)); } - if (const GRState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false)) - if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero, + if (const ProgramState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false)) + if (const ProgramState *stateFree = FreeMemAux(C, CE, stateSizeNotZero, 0, false)) { // FIXME: We should copy the content of the original buffer. - const GRState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1), + const ProgramState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1), UnknownVal(), stateFree); C.addTransition(stateRealloc); } @@ -556,7 +555,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { } void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) { - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SValBuilder &svalBuilder = C.getSValBuilder(); SVal count = state->getSVal(CE->getArg(0)); @@ -574,33 +573,40 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, if (!SymReaper.hasDeadSymbols()) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); RegionStateTy RS = state->get<RegionState>(); RegionStateTy::Factory &F = state->get_context<RegionState>(); + bool generateReport = false; + for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { if (SymReaper.isDead(I->first)) { - if (I->second.isAllocated()) { - if (ExplodedNode *N = C.generateNode()) { - if (!BT_Leak) - BT_Leak.reset(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); - } - } + if (I->second.isAllocated()) + generateReport = true; // Remove the dead symbol from the map. RS = F.remove(RS, I->first); + } } - C.generateNode(state->set<RegionState>(RS)); + + ExplodedNode *N = C.generateNode(state->set<RegionState>(RS)); + + // FIXME: This does not handle when we have multiple leaks at a single + // place. + if (N && generateReport) { + if (!BT_Leak) + BT_Leak.reset(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::checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const { - const GRState *state = B.getState(); + const ProgramState *state = B.getState(); RegionStateTy M = state->get<RegionState>(); for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) { @@ -623,7 +629,7 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { if (!retExpr) return; - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); SymbolRef Sym = state->getSVal(retExpr).getAsSymbol(); if (!Sym) @@ -640,7 +646,7 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { C.addTransition(state); } -const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond, +const ProgramState *MallocChecker::evalAssume(const ProgramState *state, SVal Cond, bool Assumption) const { // If a symblic region is assumed to NULL, set its state to AllocateFailed. // FIXME: should also check symbols assumed to non-null. @@ -657,7 +663,8 @@ const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond, } // Check if the location is a freed symbolic region. -void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const { +void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S, + CheckerContext &C) const { SymbolRef Sym = l.getLocSymbolInBase(); if (Sym) { const RefState *RS = C.getState()->get<RegionState>(Sym); @@ -675,13 +682,14 @@ void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const { } } -void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const { +void MallocChecker::checkBind(SVal location, SVal val, + const Stmt *BindS, CheckerContext &C) const { // The PreVisitBind implements the same algorithm as already used by the // Objective C ownership checker: if the pointer escaped from this scope by // assignment, let it go. However, assigning to fields of a stack-storage // structure does not transfer ownership. - const GRState *state = C.getState(); + const ProgramState *state = C.getState(); DefinedOrUnknownSVal l = cast<DefinedOrUnknownSVal>(location); // Check for null dereferences. @@ -694,7 +702,7 @@ void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const { if (Sym) { if (const RefState *RS = state->get<RegionState>(Sym)) { // If ptr is NULL, no operation is performed. - const GRState *notNullState, *nullState; + const ProgramState *notNullState, *nullState; llvm::tie(notNullState, nullState) = state->assume(l); // Generate a transition for 'nullState' to record the assumption @@ -724,7 +732,7 @@ void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const { // We no longer own this pointer. notNullState = notNullState->set<RegionState>(Sym, - RefState::getRelinquished(C.getStmt())); + RefState::getRelinquished(BindS)); } while (false); } |