From 52242a667795fd61ff3ea95b33a71ceafaad1d2a Mon Sep 17 00:00:00 2001 From: Anna Zaks Date: Fri, 3 Aug 2012 18:30:18 +0000 Subject: [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. llvm-svn: 161248 --- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 16 ++++------------ clang/test/Analysis/malloc.c | 14 +++++++++++--- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'clang') diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 5db85ecb401..0a36071cf7c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -679,14 +679,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, SymbolRef Sym = SR->getSymbol(); const RefState *RS = state->get(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(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(Sym); const RefState *RSPrev = statePrev->get(Sym); - if (!RS && !RSPrev) + if (!RS) return 0; const Stmt *S = 0; diff --git a/clang/test/Analysis/malloc.c b/clang/test/Analysis/malloc.c index 377642cc58c..964424647f6 100644 --- a/clang/test/Analysis/malloc.c +++ b/clang/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}} +} -- cgit v1.2.3