From: Anna Zaks Date: Tue, 14 Feb 2012 00:26:13 +0000 (+0000) Subject: [analyzer] Malloc Checker: realloc: add dependency between the symbols X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b276bd9cc98247331cac8b290ba278b939e53657;p=clang [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 --- 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(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(Sym, RefState::getRelinquished(CE)); - return notNullState->set(Sym, RefState::getReleased(CE)); + return state->set(Sym, RefState::getRelinquished(CE)); + return state->set(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(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(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(I.getData(), RefState::getAllocateUnchecked(RS->getStmt())); - if (RS->isAllocated()) + else if (RS->isAllocated()) state = state->set(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.