aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-02-08 23:16:56 +0000
committerAnna Zaks <ganna@apple.com>2012-02-08 23:16:56 +0000
commit91c2a1192cdd4e7b2b4ac7838c5aceef200ea251 (patch)
tree860188cbd68c645afa4285f58afe53dcaa97e925 /lib/StaticAnalyzer/Checkers/MallocChecker.cpp
parent231361ad343d655e4bbb1574ccbb4173b72dadfd (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.cpp91
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,