diff options
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 17 | ||||
-rw-r--r-- | test/Analysis/malloc.c | 51 |
2 files changed, 60 insertions, 8 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 98298c850b..9329d5251f 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -670,18 +670,22 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { if (PrtIsNull && SizeIsZero) return; + // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size). assert(!PrtIsNull); + SymbolRef FromPtr = arg0Val.getAsSymbol(); + SVal RetVal = state->getSVal(CE, LCtx); + SymbolRef ToPtr = RetVal.getAsSymbol(); + if (!FromPtr || !ToPtr) + return; // If the size is 0, free the memory. if (SizeIsZero) if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero,0,false)){ - // Bind the return value to NULL because it is now free. - // TODO: This is tricky. Does not currently work. // 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. - C.addTransition(stateFree->BindExpr(CE, LCtx, - svalBuilder.makeNull(), true)); + stateFree = stateFree->set<ReallocPairs>(ToPtr, FromPtr); + C.addTransition(stateFree); return; } @@ -690,10 +694,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { // FIXME: We should copy the content of the original buffer. ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1), UnknownVal(), stateFree); - SymbolRef FromPtr = arg0Val.getAsSymbol(); - SVal RetVal = state->getSVal(CE, LCtx); - SymbolRef ToPtr = RetVal.getAsSymbol(); - if (!stateRealloc || !FromPtr || !ToPtr) + if (!stateRealloc) return; stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr, FromPtr); C.addTransition(stateRealloc); diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c index d1d850c681..b819caa0ac 100644 --- a/test/Analysis/malloc.c +++ b/test/Analysis/malloc.c @@ -58,6 +58,57 @@ void reallocFails() { } } +void reallocSizeZero1() { + char *p = malloc(12); + char *r = realloc(p, 0); + if (!r) { + free(p); + } else { + free(r); + } +} + +void reallocSizeZero2() { + char *p = malloc(12); + char *r = realloc(p, 0); + if (!r) { + free(p); + } else { + free(r); + } + free(p); // expected-warning {{Try to free a memory block that has been released}} +} + +void reallocSizeZero3() { + char *p = malloc(12); + char *r = realloc(p, 0); + free(r); +} + +void reallocSizeZero4() { + char *r = realloc(0, 0); + free(r); +} + +void reallocSizeZero5() { + char *r = realloc(0, 0); +} + +void reallocPtrZero1() { + char *r = realloc(0, 12); // expected-warning {{Allocated memory never released.}} +} + +void reallocPtrZero2() { + char *r = realloc(0, 12); + if (r) + free(r); +} + +void reallocPtrZero3() { + char *r = realloc(0, 12); + free(r); +} + // 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. |