Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1919,20 +1919,31 @@ // state is under-constrained, assume regular realloc behavior. bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull; bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero; + bool IsC89 = !C.getLangOpts().C99 && !C.getLangOpts().CPlusPlus; - // If the ptr is NULL and the size is not 0, the call is equivalent to - // malloc(size). - if ( PrtIsNull && !SizeIsZero) { + if (PrtIsNull) { + // The C89 Draft, p.4.10.3.4 : If ptr is a null pointer, the realloc + // function behaves like the malloc function for the specified size. + // The C89 Draft, p.4.10.3 : If the size of the space requested is zero, + // the behavior is implementation-defined. + if (IsC89 && SizeIsZero) + return nullptr; + + // C99 (N1256) p.7.20.3 : If the size of the space requested is zero, the + // behavior is implementation defined : either a null pointer is returned, or + // the behavior is as if the size were some nonzero value, except that the + // returned pointer shall not be used to access an object. + // + // We keep tracking the returned pointer in case of a zero-allocation to + // check for zero-allocated memory access and to ensure that the memory is + // freed. ProgramStateRef stateMalloc = MallocMemAux(C, CE, CE->getArg(1), - UndefinedVal(), StatePtrIsNull); + UndefinedVal(), + StatePtrIsNull); return stateMalloc; } - if (PrtIsNull && SizeIsZero) - return nullptr; - // 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(); @@ -1941,8 +1952,9 @@ bool ReleasedAllocated = false; - // If the size is 0, free the memory. - if (SizeIsZero) + if (IsC89 && SizeIsZero) + // The C89 Draft, p.4.10.3.4: If size is zero and ptr is not a null + // pointer, the object it points to is freed. if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero, 0, false, ReleasedAllocated)){ // The semantics of the return value are: Index: test/Analysis/malloc-annotations.c =================================================================== --- test/Analysis/malloc-annotations.c +++ test/Analysis/malloc-annotations.c @@ -41,11 +41,6 @@ realloc(p,0); // expected-warning{{Attempt to free released memory}} } -void f2_realloc_1() { - int *p = malloc(12); - int *q = realloc(p,0); // no-warning -} - // ownership attributes tests void naf1() { int *p = my_malloc3(12); @@ -176,15 +171,6 @@ 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(); Index: test/Analysis/malloc.c =================================================================== --- test/Analysis/malloc.c +++ test/Analysis/malloc.c @@ -37,11 +37,6 @@ realloc(p,0); // expected-warning{{Attempt to free released memory}} } -void f2_realloc_1() { - int *p = malloc(12); - int *q = realloc(p,0); // no-warning -} - void reallocNotNullPtr(unsigned sizeIn) { unsigned size = 12; char *p = (char*)malloc(size); @@ -79,38 +74,22 @@ void reallocSizeZero1() { char *p = malloc(12); char *r = realloc(p, 0); - if (!r) { - free(p); // expected-warning {{Attempt to free released memory}} - } else { - free(r); - } + free(r); } void reallocSizeZero2() { char *p = malloc(12); char *r = realloc(p, 0); - if (!r) { - free(p); // expected-warning {{Attempt to free released memory}} - } else { - free(r); - } - free(p); // expected-warning {{Attempt to free released memory}} -} +} // expected-warning {{Potential leak of memory pointed to by}} void reallocSizeZero3() { - char *p = malloc(12); - char *r = realloc(p, 0); - free(r); -} - -void reallocSizeZero4() { char *r = realloc(0, 0); free(r); } -void reallocSizeZero5() { +void reallocSizeZero4() { char *r = realloc(0, 0); -} +} // expected-warning {{Potential leak of memory pointed to by}} void reallocPtrZero1() { char *r = realloc(0, 12); @@ -263,21 +242,21 @@ void CheckUseZeroAllocated7() { int *p = realloc(0, 0); - *p = 1; //TODO: warn about use of zero-allocated memory + *p = 1; // expected-warning {{Use of zero-allocated memory}} free(p); } void CheckUseZeroAllocated8() { int *p = malloc(8); int *q = realloc(p, 0); - *q = 1; //TODO: warn about use of zero-allocated memory + *q = 1; // expected-warning {{Use of zero-allocated memory}} free(q); } void CheckUseZeroAllocated9() { int *p = realloc(0, 0); int *q = realloc(p, 0); - *q = 1; //TODO: warn about use of zero-allocated memory + *q = 1; // expected-warning {{Use of zero-allocated memory}} free(q); } @@ -339,15 +318,6 @@ 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(); Index: test/Analysis/realloc-C89.c =================================================================== --- test/Analysis/realloc-C89.c +++ test/Analysis/realloc-C89.c @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -std=c89 %s +typedef __typeof(sizeof(int)) size_t; +void *malloc(size_t); +void *realloc(void *ptr, size_t size); + +void reallocSizeZero1() { + char *p = malloc(12); + char *r = realloc(p, 0); + if (!r) { + free(p); // expected-warning {{Attempt to free released memory}} + } else { + free(r); + } +} + +void reallocSizeZero2() { + char *p = malloc(12); + char *r = realloc(p, 0); + if (!r) { + free(p); // expected-warning {{Attempt to free released memory}} + } else { + free(r); + } + free(p); // expected-warning {{Attempt to free released memory}} +} + +void reallocSizeZero3() { + char *p = malloc(12); + char *r = realloc(p, 0); + free(r); // no warning +} + +void reallocSizeZero4() { + char *r = realloc(0, 0); + free(r); // no warning +} + +void reallocSizeZero5() { + char *r = realloc(0, 0); +} // no warning + +void CheckUseZeroAllocated1() { + int *p = realloc(0, 0); + *p = 1; // no warning + free(p); +} + +void CheckUseZeroAllocated8() { + int *p = malloc(8); + int *q = realloc(p, 0); + *q = 1; // no warning + free(q); +} + +void CheckUseZeroAllocated9() { + int *p = realloc(0, 0); + int *q = realloc(p, 0); + *q = 1; // no warning + free(q); +}