aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-08-03 18:30:18 +0000
committerAnna Zaks <ganna@apple.com>2012-08-03 18:30:18 +0000
commitede875b794e8f35aa1432e61610ea6e84360b6d3 (patch)
tree3c9025452661ef878a4099cc413c92c8cab5a9ee
parentf1aae3bc4e43fca03324150d7089856b7cfdc023 (diff)
[analyzer] Malloc: track non-allocated but freed memory
There is no reason why we should not track the memory which was not allocated in the current function, but was freed there. This would allow to catch more use-after-free and double free with no/limited IPA. Also fix a realloc issue which surfaced as the result of this patch. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161248 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp16
-rw-r--r--test/Analysis/malloc.c14
2 files changed, 15 insertions, 15 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 5db85ecb40..0a36071cf7 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -679,14 +679,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
SymbolRef Sym = SR->getSymbol();
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 0;
-
// Check double free.
- if (RS->isReleased() || RS->isRelinquished()) {
+ if (RS && (RS->isReleased() || RS->isRelinquished())) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_DoubleFree)
BT_DoubleFree.reset(
@@ -902,10 +896,8 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero,0,false)){
// The semantics of the return value are:
// If size was equal to 0, either NULL or a pointer suitable to be passed
- // to free() is returned.
- stateFree = stateFree->set<ReallocPairs>(ToPtr,
- ReallocPair(FromPtr, FreesOnFail));
- C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
+ // to free() is returned. We just free the input pointer and do not add
+ // any constrains on the output pointer.
return stateFree;
}
@@ -1518,7 +1510,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
const RefState *RS = state->get<RegionState>(Sym);
const RefState *RSPrev = statePrev->get<RegionState>(Sym);
- if (!RS && !RSPrev)
+ if (!RS)
return 0;
const Stmt *S = 0;
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index 377642cc58..964424647f 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -69,7 +69,7 @@ void reallocSizeZero1() {
char *p = malloc(12);
char *r = realloc(p, 0);
if (!r) {
- free(p);
+ free(p); // expected-warning {{Attempt to free released memory}}
} else {
free(r);
}
@@ -79,7 +79,7 @@ void reallocSizeZero2() {
char *p = malloc(12);
char *r = realloc(p, 0);
if (!r) {
- free(p);
+ free(p); // expected-warning {{Attempt to free released memory}}
} else {
free(r);
}
@@ -321,7 +321,7 @@ void nullFree() {
void paramFree(int *p) {
myfoo(p);
free(p); // no warning
- myfoo(p); // TODO: This should be a warning.
+ myfoo(p); // expected-warning {{Use of memory after it is freed}}
}
int* mallocEscapeRet() {
@@ -999,3 +999,11 @@ void foo (xpc_connection_t peer) {
xpc_connection_resume(peer);
}
+// Make sure we catch errors when we free in a function which does not allocate memory.
+void freeButNoMalloc(int *p, int x){
+ if (x) {
+ free(p);
+ //user forgot a return here.
+ }
+ free(p); // expected-warning {{Attempt to free released memory}}
+}