diff options
author | Lenny Maiorani <lenny@colorado.edu> | 2011-04-27 14:49:29 +0000 |
---|---|---|
committer | Lenny Maiorani <lenny@colorado.edu> | 2011-04-27 14:49:29 +0000 |
commit | 005b5c1aee6bc44412dfbb06685d23d0967522f7 (patch) | |
tree | 7a574ef20cf50e5a3de55d597530146af2a2794b /clang | |
parent | 085ad3b81abb71cf80cce2d6e3f3ca81b3bd31b8 (diff) | |
download | bcm5719-llvm-005b5c1aee6bc44412dfbb06685d23d0967522f7.tar.gz bcm5719-llvm-005b5c1aee6bc44412dfbb06685d23d0967522f7.zip |
More accurately model realloc() when the size argument is 0. realloc() with a size of 0 is equivalent to free(). The memory region should be marked as free and not used again.
Unit tests f2_realloc_0(), f6_realloc(), and f7_realloc() contributed by Marshall Clow <mclow.lists@gmail.com>. Thanks!
llvm-svn: 130303
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 38 | ||||
-rw-r--r-- | clang/test/Analysis/malloc.c | 26 |
2 files changed, 53 insertions, 11 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index a7655c4fb9d..91002158c57 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -501,8 +501,24 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { DefinedOrUnknownSVal PtrEQ = svalBuilder.evalEQ(state, arg0Val, svalBuilder.makeNull()); - // If the ptr is NULL, the call is equivalent to malloc(size). - if (const GRState *stateEqual = state->assume(PtrEQ, true)) { + // Get the size argument. If there is no size arg then give up. + const Expr *Arg1 = CE->getArg(1); + if (!Arg1) + return; + + // Get the value of the size argument. + DefinedOrUnknownSVal Arg1Val = + cast<DefinedOrUnknownSVal>(state->getSVal(Arg1)); + + // Compare the size argument to 0. + DefinedOrUnknownSVal SizeZero = + svalBuilder.evalEQ(state, Arg1Val, + svalBuilder.makeIntValWithPtrWidth(0, false)); + + // If the ptr is NULL and the size is not 0, the call is equivalent to + // malloc(size). + const GRState *stateEqual = state->assume(PtrEQ, true); + if (stateEqual && state->assume(SizeZero, false)) { // Hack: set the NULL symbolic region to released to suppress false warning. // In the future we should add more states for allocated regions, e.g., // CheckedNull, CheckedNonNull. @@ -517,17 +533,17 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { } if (const GRState *stateNotEqual = state->assume(PtrEQ, false)) { - const Expr *Arg1 = CE->getArg(1); - DefinedOrUnknownSVal Arg1Val = - cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1)); - DefinedOrUnknownSVal SizeZero = - svalBuilder.evalEQ(stateNotEqual, Arg1Val, - svalBuilder.makeIntValWithPtrWidth(0, false)); - + // If the size is 0, free the memory. if (const GRState *stateSizeZero = stateNotEqual->assume(SizeZero, true)) - if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero, 0, false)) - C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true)); + if (const GRState *stateFree = + FreeMemAux(C, CE, stateSizeZero, 0, false)) { + + // Add the state transition to set input pointer argument to be free. + C.addTransition(stateFree); + // Bind the return value to UndefinedVal because it is now free. + C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true)); + } if (const GRState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false)) if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero, 0, false)) { diff --git a/clang/test/Analysis/malloc.c b/clang/test/Analysis/malloc.c index c13e15257be..f9af199b5fa 100644 --- a/clang/test/Analysis/malloc.c +++ b/clang/test/Analysis/malloc.c @@ -33,6 +33,17 @@ void f2() { free(p); // expected-warning{{Try to free a memory block that has been released}} } +void f2_realloc_0() { + int *p = malloc(12); + realloc(p,0); + realloc(p,0); // expected-warning{{Try to free a memory block that has been released}} +} + +void f2_realloc_1() { + int *p = malloc(12); + int *q = realloc(p,0); // expected-warning{{Assigned value is garbage or undefined}} +} + // ownership attributes tests void naf1() { int *p = my_malloc3(12); @@ -166,6 +177,15 @@ void f6() { free(p); } +void f6_realloc() { + int *p = malloc(12); + if (!p) + return; // no-warning + else + realloc(p,0); +} + + char *doit2(); void pr6069() { char *buf = doit2(); @@ -182,6 +202,12 @@ void f7() { x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}} } +void f7_realloc() { + char *x = (char*) malloc(4); + realloc(x,0); + x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}} +} + void PR6123() { int *x = malloc(11); // expected-warning{{Cast a region whose size is not a multiple of the destination type size.}} } |