diff options
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 15 | ||||
-rw-r--r-- | test/Analysis/malloc.c | 41 |
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. |