forked from OSchip/llvm-project
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
This commit is contained in:
parent
085ad3b81a
commit
005b5c1aee
|
@ -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)) {
|
||||
|
|
|
@ -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.}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue