diff options
author | Anna Zaks <ganna@apple.com> | 2012-02-08 23:16:56 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2012-02-08 23:16:56 +0000 |
commit | 91c2a1192cdd4e7b2b4ac7838c5aceef200ea251 (patch) | |
tree | 860188cbd68c645afa4285f58afe53dcaa97e925 /lib/StaticAnalyzer/Checkers/MallocChecker.cpp | |
parent | 231361ad343d655e4bbb1574ccbb4173b72dadfd (diff) |
[analyzer] MallocChecker: implement pessimistic version of the checker,
which allows values to escape through unknown calls.
Assumes all calls but the malloc family are unknown.
Also, catch a use-after-free when a pointer is passed to a
function after a call to free (previously, you had to explicitly
dereference the pointer value).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150112 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/MallocChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 91 |
1 files changed, 62 insertions, 29 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index b14b400202..c110e0f6f8 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -131,6 +131,10 @@ private: void ReallocMem(CheckerContext &C, const CallExpr *CE) const; static void CallocMem(CheckerContext &C, const CallExpr *CE); + bool checkEscape(SymbolRef Sym, const Stmt *S, CheckerContext &C) const; + bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, + const Stmt *S = 0) const; + 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; @@ -186,6 +190,7 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { return; } + if (Filter.CMallocOptimistic) // Check all the attributes, if there are any. // There can be multiple of these attributes. if (FD->hasAttrs()) { @@ -206,6 +211,22 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { } } } + + if (Filter.CMallocPessimistic) { + ProgramStateRef State = C.getState(); + // The pointer might escape through a function call. + for (CallExpr::const_arg_iterator I = CE->arg_begin(), + E = CE->arg_end(); I != E; ++I) { + const Expr *A = *I; + if (A->getType().getTypePtr()->isAnyPointerType()) { + SymbolRef Sym = State->getSVal(A, C.getLocationContext()).getAsSymbol(); + if (!Sym) + return; + checkEscape(Sym, A, C); + checkUseAfterFree(Sym, C, A); + } + } + } } void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { @@ -642,32 +663,36 @@ void MallocChecker::checkEndPath(CheckerContext &Ctx) const { } } -void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { - const Expr *retExpr = S->getRetValue(); - if (!retExpr) - return; - +bool MallocChecker::checkEscape(SymbolRef Sym, const Stmt *S, + CheckerContext &C) const { ProgramStateRef state = C.getState(); - - SymbolRef Sym = state->getSVal(retExpr, C.getLocationContext()).getAsSymbol(); - if (!Sym) - return; - const RefState *RS = state->get<RegionState>(Sym); if (!RS) - return; + return false; - // FIXME: check other cases. - if (RS->isAllocated()) + if (RS->isAllocated()) { state = state->set<RegionState>(Sym, RefState::getEscaped(S)); + C.addTransition(state); + return true; + } + return false; +} - C.addTransition(state); +void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { + const Expr *E = S->getRetValue(); + if (!E) + return; + SymbolRef Sym = C.getState()->getSVal(E, C.getLocationContext()).getAsSymbol(); + if (!Sym) + return; + + checkEscape(Sym, S, C); } ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state, SVal Cond, bool Assumption) const { - // If a symblic region is assumed to NULL, set its state to AllocateFailed. + // If a symbolic region is assumed to NULL, set its state to AllocateFailed. // FIXME: should also check symbols assumed to non-null. RegionStateTy RS = state->get<RegionState>(); @@ -681,24 +706,32 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state, return state; } +bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, + const Stmt *S) const { + assert(Sym); + const RefState *RS = C.getState()->get<RegionState>(Sym); + if (RS && RS->isReleased()) { + if (ExplodedNode *N = C.addTransition()) { + if (!BT_UseFree) + BT_UseFree.reset(new BuiltinBug("Use dynamically allocated memory " + "after it is freed.")); + + BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(),N); + if (S) + R->addRange(S->getSourceRange()); + C.EmitReport(R); + return true; + } + } + return false; +} + // Check if the location is a freed symbolic region. 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); - if (RS && RS->isReleased()) { - if (ExplodedNode *N = C.addTransition()) { - if (!BT_UseFree) - BT_UseFree.reset(new BuiltinBug("Use dynamically allocated memory " - "after it is freed.")); - - BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(), - N); - C.EmitReport(R); - } - } - } + if (Sym) + checkUseAfterFree(Sym, C); } void MallocChecker::checkBind(SVal location, SVal val, |