aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-02-14 00:26:13 +0000
committerAnna Zaks <ganna@apple.com>2012-02-14 00:26:13 +0000
commitb276bd9cc98247331cac8b290ba278b939e53657 (patch)
tree04ae886c76f99dff195b6e946275551cb3d7f073
parentd764437c9ce6feae11a9fca35bbc4ebc004f69e0 (diff)
[analyzer] Malloc Checker: realloc: add dependency between the symbols
in realloc map. If there is no dependency, the reallocated ptr will get garbage collected before we know that realloc failed, which would lead us to missing a memory leak warning. Also added new test cases, which we can handle now. Plus minor cleanups. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150446 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp15
-rw-r--r--test/Analysis/malloc.c41
2 files changed, 47 insertions, 9 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 9329d5251f..7cbb49e2d8 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -409,17 +409,12 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
if (!isa<Loc>(location))
return 0;
- // FIXME: Technically using 'Assume' here can result in a path
- // bifurcation. In such cases we need to return two states, not just one.
+ // The explicit NULL case, no operation is performed.
ProgramStateRef notNullState, nullState;
llvm::tie(notNullState, nullState) = state->assume(location);
-
- // The explicit NULL case, no operation is performed.
if (nullState && !notNullState)
return 0;
- assert(notNullState);
-
// Unknown values could easily be okay
// Undefined values are handled elsewhere
if (ArgVal.isUnknownOrUndef())
@@ -490,8 +485,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// Normal free.
if (Hold)
- return notNullState->set<RegionState>(Sym, RefState::getRelinquished(CE));
- return notNullState->set<RegionState>(Sym, RefState::getReleased(CE));
+ return state->set<RegionState>(Sym, RefState::getRelinquished(CE));
+ return state->set<RegionState>(Sym, RefState::getReleased(CE));
}
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
@@ -685,6 +680,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
// If size was equal to 0, either NULL or a pointer suitable to be passed
// to free() is returned.
stateFree = stateFree->set<ReallocPairs>(ToPtr, FromPtr);
+ C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
C.addTransition(stateFree);
return;
}
@@ -697,6 +693,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
if (!stateRealloc)
return;
stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr, FromPtr);
+ C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
C.addTransition(stateRealloc);
return;
}
@@ -918,7 +915,7 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
if (RS->isReleased())
state = state->set<RegionState>(I.getData(),
RefState::getAllocateUnchecked(RS->getStmt()));
- if (RS->isAllocated())
+ else if (RS->isAllocated())
state = state->set<RegionState>(I.getData(),
RefState::getReleased(RS->getStmt()));
}
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index b819caa0ac..0aa9291255 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -109,6 +109,47 @@ void reallocPtrZero3() {
free(r);
}
+void reallocRadar6337483_1() {
+ char *buf = malloc(100);
+ buf = (char*)realloc(buf, 0x1000000);
+ if (!buf) {
+ return;// expected-warning {{Allocated memory never released.}}
+ }
+ free(buf);
+}
+
+void reallocRadar6337483_2() {
+ char *buf = malloc(100);
+ char *buf2 = (char*)realloc(buf, 0x1000000);
+ if (!buf2) { // expected-warning {{Allocated memory never released.}}
+ ;
+ } else {
+ free(buf2);
+ }
+}
+
+void reallocRadar6337483_3() {
+ char * buf = malloc(100);
+ char * tmp;
+ tmp = (char*)realloc(buf, 0x1000000);
+ if (!tmp) {
+ free(buf);
+ return;
+ }
+ buf = tmp;
+ free(buf);
+}
+
+void reallocRadar6337483_4() {
+ char *buf = malloc(100);
+ char *buf2 = (char*)realloc(buf, 0x1000000);
+ if (!buf2) {
+ return; // expected-warning {{Allocated memory never released.}}
+ } else {
+ free(buf2);
+ }
+}
+
// This case tests that storing malloc'ed memory to a static variable which is
// then returned is not leaked. In the absence of known contracts for functions
// or inter-procedural analysis, this is a conservative answer.