Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -152,6 +152,18 @@ } }; +/// \class ReallocSizeZero +/// \brief Indicates zero-size reallocation. Used to catch references to +/// zero-allocated memory returned by 'realloc(ptr, 0)'. +struct ReallocSizeZero { + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddString("ReallocSizeZero"); + }; + bool operator==(const ReallocSizeZero &X) const { + return true; + } +}; + typedef std::pair LeakInfo; class MallocChecker : public Checkerget(Sym); - if (!RS) - return State; // TODO: change to assert(RS); after realloc() will - // guarantee have a RegionState attached. - - if (!RS->isAllocated()) - return State; - - return TrueState->set(Sym, - RefState::getAllocatedOfSizeZero(RS)); + if (RS) { + if (RS->isAllocated()) + return TrueState->set(Sym, + RefState::getAllocatedOfSizeZero(RS)); + else + return State; + } else { + // Case of zero-size realloc. Historically 'realloc(ptr, 0)' is treated as + // 'free(ptr)' and the returned value from 'realloc(ptr, 0)' is not + // tracked. Here we add ReallocSizeZeroFlag mark to catch references + // to zero-allocated memory. + return TrueState->set(Sym, ReallocSizeZero()); + } } // Assume the value is non-zero going forward. @@ -1488,6 +1505,9 @@ Optional MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym, bool IsALeakCheck) const { + if (C.getState()->get(Sym)) + return CK_MallocChecker; + const RefState *RS = C.getState()->get(Sym); assert(RS); return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck); @@ -1929,7 +1949,7 @@ } if (PrtIsNull && SizeIsZero) - return nullptr; + return State; // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size). assert(!PrtIsNull); @@ -2291,10 +2311,14 @@ void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C, const Stmt *S) const { assert(Sym); - const RefState *RS = C.getState()->get(Sym); - if (RS && RS->isAllocatedOfSizeZero()) - ReportUseZeroAllocated(C, RS->getStmt()->getSourceRange(), Sym); + if (const RefState *RS = C.getState()->get(Sym)) { + if (RS->isAllocatedOfSizeZero()) + ReportUseZeroAllocated(C, RS->getStmt()->getSourceRange(), Sym); + } + else if (C.getState()->get(Sym)) { + ReportUseZeroAllocated(C, S->getSourceRange(), Sym); + } } bool MallocChecker::checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const { Index: test/Analysis/malloc.c =================================================================== --- test/Analysis/malloc.c +++ test/Analysis/malloc.c @@ -263,21 +263,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); }