Hi jordan_rose,
This duplication was motivated by the following:
- FIXME from unix.API stating "Eventually these should be rolled into the
MallocChecker, but right now they're more basic and valuable for widespread
use."
- an idea to extend the check to handle zero size allocation by 'new' and
'new[]' in the sequel.
- create the base for implementation of undefbehavior.ZeroAllocDereference
checker.
The patch is a scratch, may it make sense to make '0 size allocation' the
separate checker to at least preserve handling of zero-size realloc unchanged.
I suggest the following logic for handling zero-size realloc:
1) if the returned value of realloc(p, 0) is not assigned then silently treat
it as simple 'free' (the old behavior of unix.Malloc)
2) if the returned value is assigned then fire '0 size allocation' warning as
the usage of the returned pointer is not safe.
Specification C11 n1570, 7.22.3.1 says: "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."
Usage of the returned pointer is planned to be a matter of other checkers
(undefbehavior.ZeroAllocDereference + maybe another checker that checks for
usage of returned pointer in comparisons)
Please review!
http://reviews.llvm.org/D6178
Files:
lib/StaticAnalyzer/Checkers/MallocChecker.cpp
test/Analysis/malloc-annotations.c
test/Analysis/malloc.c
Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -160,10 +160,11 @@
{
public:
MallocChecker()
- : II_malloc(nullptr), II_free(nullptr), II_realloc(nullptr),
- II_calloc(nullptr), II_valloc(nullptr), II_reallocf(nullptr),
- II_strndup(nullptr), II_strdup(nullptr), II_kmalloc(nullptr),
- II_if_nameindex(nullptr), II_if_freenameindex(nullptr) {}
+ : II_alloca(nullptr), II_alloca_builtin(nullptr), II_malloc(nullptr),
+ II_free(nullptr), II_realloc(nullptr), II_calloc(nullptr),
+ II_valloc(nullptr), II_reallocf(nullptr), II_strndup(nullptr),
+ II_strdup(nullptr), II_kmalloc(nullptr), II_if_nameindex(nullptr),
+ II_if_freenameindex(nullptr) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
@@ -218,9 +219,11 @@
mutable std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds];
mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
- mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
- *II_valloc, *II_reallocf, *II_strndup, *II_strdup,
- *II_kmalloc, *II_if_nameindex, *II_if_freenameindex;
+ mutable std::unique_ptr<BugType> BT_MallocZero[CK_NumCheckKinds];
+ mutable IdentifierInfo *II_alloca, *II_alloca_builtin, *II_malloc, *II_free,
+ *II_realloc, *II_calloc, *II_valloc, *II_reallocf,
+ *II_strndup, *II_strdup, *II_kmalloc, *II_if_nameindex,
+ *II_if_freenameindex;
mutable Optional<uint64_t> KernelZeroFlagVal;
void initIdentifierInfo(ASTContext &C) const;
@@ -252,22 +255,27 @@
MemoryOperationKind MemKind) const;
bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const;
///@}
+
+ ProgramStateRef BasicAllocationCheck(CheckerContext &C, const CallExpr *CE,
+ const unsigned NumArgs,
+ const unsigned SizeArg,
+ ProgramStateRef State) const;
+
+ ProgramStateRef CheckCallocZero(CheckerContext &C, const CallExpr *CE,
+ ProgramStateRef State) const;
+
ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
const CallExpr *CE,
- const OwnershipAttr* Att) const;
+ const OwnershipAttr* Att,
+ ProgramStateRef State) const;
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
- const Expr *SizeEx, SVal Init,
- ProgramStateRef State,
- AllocationFamily Family = AF_Malloc) {
- return MallocMemAux(C, CE,
- State->getSVal(SizeEx, C.getLocationContext()),
- Init, State, Family);
- }
-
+ const Expr *SizeEx, SVal Init,
+ ProgramStateRef State,
+ AllocationFamily Family = AF_Malloc);
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
- SVal SizeEx, SVal Init,
- ProgramStateRef State,
- AllocationFamily Family = AF_Malloc);
+ SVal SizeEx, SVal Init,
+ ProgramStateRef State,
+ AllocationFamily Family = AF_Malloc);
// Check if this malloc() for special flags. At present that means M_ZERO or
// __GFP_ZERO (in which case, treat it like calloc).
@@ -281,7 +289,8 @@
AllocationFamily Family = AF_Malloc);
ProgramStateRef FreeMemAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att) const;
+ const OwnershipAttr* Att,
+ ProgramStateRef State) const;
ProgramStateRef FreeMemAux(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, unsigned Num,
bool Hold,
@@ -295,8 +304,10 @@
bool ReturnsNullOnFailure = false) const;
ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE,
- bool FreesMemOnFailure) const;
- static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE);
+ bool FreesMemOnFailure,
+ ProgramStateRef State) const;
+ static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
+ ProgramStateRef State);
///\brief Check if the memory associated with this symbol was released.
bool isReleased(SymbolRef Sym, CheckerContext &C) const;
@@ -337,6 +348,8 @@
///@}
static bool SummarizeValue(raw_ostream &os, SVal V);
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
+ void ReportZeroByteAllocation(CheckerContext &C, ProgramStateRef FalseState,
+ const Expr *Arg, const Expr *AllocExpr) const;
void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
const Expr *DeallocExpr) const;
void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range,
@@ -497,6 +510,8 @@
void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {
if (II_malloc)
return;
+ II_alloca = &Ctx.Idents.get("alloca");
+ II_alloca_builtin = &Ctx.Idents.get("__builtin_alloca");
II_malloc = &Ctx.Idents.get("malloc");
II_free = &Ctx.Idents.get("free");
II_realloc = &Ctx.Idents.get("realloc");
@@ -545,9 +560,10 @@
}
if (Family == AF_Malloc && CheckAlloc) {
- if (FunI == II_malloc || FunI == II_realloc || FunI == II_reallocf ||
- FunI == II_calloc || FunI == II_valloc || FunI == II_strdup ||
- FunI == II_strndup || FunI == II_kmalloc)
+ if (FunI == II_alloca || FunI == II_alloca_builtin || FunI == II_malloc ||
+ FunI == II_realloc || FunI == II_reallocf || FunI == II_calloc ||
+ FunI == II_valloc || FunI == II_strdup || FunI == II_strndup ||
+ FunI == II_kmalloc)
return true;
}
@@ -710,6 +726,9 @@
if (FunI == II_malloc) {
if (CE->getNumArgs() < 1)
return;
+ else if (CE->getNumArgs() == 1)
+ State = BasicAllocationCheck(C, CE, 1, 0, State);
+
if (CE->getNumArgs() < 3) {
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
} else if (CE->getNumArgs() == 3) {
@@ -731,20 +750,25 @@
if (CE->getNumArgs() < 1)
return;
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ State = BasicAllocationCheck(C, CE, 1, 0, State);
} else if (FunI == II_realloc) {
- State = ReallocMem(C, CE, false);
+ State = ReallocMem(C, CE, false, State);
+ State = BasicAllocationCheck(C, CE, 2, 1, State);
} else if (FunI == II_reallocf) {
- State = ReallocMem(C, CE, true);
+ State = ReallocMem(C, CE, true, State);
+ State = BasicAllocationCheck(C, CE, 2, 1, State);
} else if (FunI == II_calloc) {
- State = CallocMem(C, CE);
+ State = CallocMem(C, CE, State);
+ State = CheckCallocZero(C, CE, State);
} else if (FunI == II_free) {
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
} else if (FunI == II_strdup) {
State = MallocUpdateRefState(C, CE, State);
} else if (FunI == II_strndup) {
State = MallocUpdateRefState(C, CE, State);
- }
- else if (isStandardNewDelete(FD, C.getASTContext())) {
+ } else if (FunI == II_alloca || FunI == II_alloca_builtin) {
+ State = BasicAllocationCheck(C, CE, 1, 0, State);
+ } else if (isStandardNewDelete(FD, C.getASTContext())) {
// Process direct calls to operator new/new[]/delete/delete[] functions
// as distinct from new/new[]/delete/delete[] expressions that are
// processed by the checkPostStmt callbacks for CXXNewExpr and
@@ -778,18 +802,101 @@
for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
switch (I->getOwnKind()) {
case OwnershipAttr::Returns:
- State = MallocMemReturnsAttr(C, CE, I);
+ State = MallocMemReturnsAttr(C, CE, I, State);
break;
case OwnershipAttr::Takes:
case OwnershipAttr::Holds:
- State = FreeMemAttr(C, CE, I);
+ State = FreeMemAttr(C, CE, I, State);
break;
}
}
}
C.addTransition(State);
}
+//===----------------------------------------------------------------------===//
+// "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc"
+// with allocation size 0
+//===----------------------------------------------------------------------===//
+
+// Returns true if we try to do a zero byte allocation, false otherwise.
+// Fills in TrueState and TalseState.
+static bool IsZeroByteAllocation(ProgramStateRef State,
+ const SVal ArgVal,
+ ProgramStateRef *TrueState,
+ ProgramStateRef *FalseState) {
+ std::tie(*TrueState, *FalseState) =
+ State->assume(ArgVal.castAs<DefinedSVal>());
+
+ return (*FalseState && !*TrueState);
+}
+
+// Does a basic check for 0-sized allocations suitable for most of the below
+// functions (modulo "calloc")
+ProgramStateRef MallocChecker::BasicAllocationCheck(CheckerContext &C,
+ const CallExpr *CE,
+ const unsigned NumArgs,
+ const unsigned SizeArg,
+ ProgramStateRef State) const {
+ if (!State)
+ return nullptr;
+
+ // Sanity check for the correct number of arguments
+ if (CE->getNumArgs() != NumArgs)
+ return nullptr;
+
+ // Check if the allocation size is 0.
+ ProgramStateRef TrueState = nullptr, FalseState = nullptr;
+ const Expr *Arg = CE->getArg(SizeArg);
+ SVal ArgVal = State->getSVal(Arg, C.getLocationContext());
+
+ if (ArgVal.isUnknownOrUndef())
+ return nullptr;
+
+ // Is the value perfectly constrained to zero?
+ if (IsZeroByteAllocation(State, ArgVal, &TrueState, &FalseState)) {
+ ReportZeroByteAllocation(C, FalseState, Arg, CE);
+ return nullptr;
+ }
+ // Assume the value is non-zero going forward.
+ assert(TrueState);
+ return TrueState;
+}
+
+ProgramStateRef MallocChecker::CheckCallocZero(CheckerContext &C,
+ const CallExpr *CE,
+ ProgramStateRef State) const {
+ if (!State)
+ return nullptr;
+
+ unsigned int NArgs = CE->getNumArgs();
+ if (NArgs != 2)
+ return nullptr;
+
+ ProgramStateRef TrueState = nullptr, FalseState = nullptr;
+
+ unsigned int i;
+ for (i = 0; i < NArgs; i++) {
+ const Expr *Arg = CE->getArg(i);
+ SVal ArgVal = State->getSVal(Arg, C.getLocationContext());
+ if (ArgVal.isUnknownOrUndef()) {
+ if (i == 0)
+ continue;
+ else
+ return nullptr;
+ }
+
+ if (IsZeroByteAllocation(State, ArgVal, &TrueState, &FalseState)) {
+ ReportZeroByteAllocation(C, FalseState, Arg, CE);
+ return nullptr;
+ }
+ }
+
+ // Assume the value is non-zero going forward.
+ assert(TrueState);
+ return TrueState;
+}
+
static QualType getDeepPointeeType(QualType T) {
QualType Result = T, PointeeType = T->getPointeeType();
while (!PointeeType.isNull()) {
@@ -919,22 +1026,40 @@
ProgramStateRef
MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr *Att) const {
+ const OwnershipAttr *Att,
+ ProgramStateRef State) const {
+ if (!State)
+ return nullptr;
+
if (Att->getModule() != II_malloc)
return nullptr;
OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
if (I != E) {
- return MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), C.getState());
+ return MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), State);
}
- return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), C.getState());
+ return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), State);
+}
+
+ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
+ const CallExpr *CE,
+ const Expr *SizeEx, SVal Init,
+ ProgramStateRef State,
+ AllocationFamily Family) {
+ if (!State)
+ return nullptr;
+
+ return MallocMemAux(C, CE, State->getSVal(SizeEx, C.getLocationContext()),
+ Init, State, Family);
}
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
const CallExpr *CE,
SVal Size, SVal Init,
ProgramStateRef State,
AllocationFamily Family) {
+ if (!State)
+ return nullptr;
// We expect the malloc functions to return a pointer.
if (!Loc::isLocType(CE->getType()))
@@ -976,6 +1101,9 @@
const Expr *E,
ProgramStateRef State,
AllocationFamily Family) {
+ if (!State)
+ return nullptr;
+
// Get the return value.
SVal retVal = State->getSVal(E, C.getLocationContext());
@@ -992,11 +1120,14 @@
ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
const CallExpr *CE,
- const OwnershipAttr *Att) const {
+ const OwnershipAttr *Att,
+ ProgramStateRef State) const {
+ if (!State)
+ return nullptr;
+
if (Att->getModule() != II_malloc)
return nullptr;
- ProgramStateRef State = C.getState();
bool ReleasedAllocated = false;
for (const auto &Arg : Att->args()) {
@@ -1011,15 +1142,18 @@
ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const CallExpr *CE,
- ProgramStateRef state,
+ ProgramStateRef State,
unsigned Num,
bool Hold,
bool &ReleasedAllocated,
bool ReturnsNullOnFailure) const {
+ if (!State)
+ return nullptr;
+
if (CE->getNumArgs() < (Num + 1))
return nullptr;
- return FreeMemAux(C, CE->getArg(Num), CE, state, Hold,
+ return FreeMemAux(C, CE->getArg(Num), CE, State, Hold,
ReleasedAllocated, ReturnsNullOnFailure);
}
@@ -1152,6 +1286,9 @@
bool &ReleasedAllocated,
bool ReturnsNullOnFailure) const {
+ if (!State)
+ return nullptr;
+
SVal ArgVal = State->getSVal(ArgExpr, C.getLocationContext());
if (!ArgVal.getAs<DefinedOrUnknownSVal>())
return nullptr;
@@ -1407,6 +1544,37 @@
}
}
+void MallocChecker::ReportZeroByteAllocation(CheckerContext &C,
+ ProgramStateRef FalseState,
+ const Expr *Arg,
+ const Expr *AllocExpr) const {
+ if (!ChecksEnabled[CK_MallocOptimistic] &&
+ !ChecksEnabled[CK_MallocPessimistic])
+ return;
+
+ auto CheckKind = getCheckIfTracked(C, AllocExpr);
+ if (!CheckKind.hasValue())
+ return;
+
+ if (ExplodedNode *N = C.generateSink(FalseState)) {
+
+ if (!BT_MallocZero[*CheckKind])
+ BT_MallocZero[*CheckKind].reset(new BugType(
+ CheckNames[*CheckKind], "Zero allocation", "Memory Error"));
+
+ SmallString<256> S;
+ llvm::raw_svector_ostream os(S);
+ os << "Call to '";
+ printAllocDeallocName(os, C, AllocExpr);
+ os << "' has an allocation size of 0 bytes";
+ BugReport *Report = new BugReport(*BT_MallocZero[*CheckKind], os.str(), N);
+
+ Report->addRange(Arg->getSourceRange());
+ bugreporter::trackNullOrUndefValue(N, Arg, *Report);
+ C.emitReport(Report);
+ }
+}
+
void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
SourceRange Range,
const Expr *DeallocExpr) const {
@@ -1655,43 +1823,46 @@
ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
const CallExpr *CE,
- bool FreesOnFail) const {
+ bool FreesOnFail,
+ ProgramStateRef State) const {
+ if (!State)
+ return nullptr;
+
if (CE->getNumArgs() < 2)
return nullptr;
- ProgramStateRef state = C.getState();
const Expr *arg0Expr = CE->getArg(0);
const LocationContext *LCtx = C.getLocationContext();
- SVal Arg0Val = state->getSVal(arg0Expr, LCtx);
+ SVal Arg0Val = State->getSVal(arg0Expr, LCtx);
if (!Arg0Val.getAs<DefinedOrUnknownSVal>())
return nullptr;
DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();
SValBuilder &svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal PtrEQ =
- svalBuilder.evalEQ(state, arg0Val, svalBuilder.makeNull());
+ svalBuilder.evalEQ(State, arg0Val, svalBuilder.makeNull());
// Get the size argument. If there is no size arg then give up.
const Expr *Arg1 = CE->getArg(1);
if (!Arg1)
return nullptr;
// Get the value of the size argument.
- SVal Arg1ValG = state->getSVal(Arg1, LCtx);
+ SVal Arg1ValG = State->getSVal(Arg1, LCtx);
if (!Arg1ValG.getAs<DefinedOrUnknownSVal>())
return nullptr;
DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>();
// Compare the size argument to 0.
DefinedOrUnknownSVal SizeZero =
- svalBuilder.evalEQ(state, Arg1Val,
+ svalBuilder.evalEQ(State, Arg1Val,
svalBuilder.makeIntValWithPtrWidth(0, false));
ProgramStateRef StatePtrIsNull, StatePtrNotNull;
- std::tie(StatePtrIsNull, StatePtrNotNull) = state->assume(PtrEQ);
+ std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
ProgramStateRef StateSizeIsZero, StateSizeNotZero;
- std::tie(StateSizeIsZero, StateSizeNotZero) = state->assume(SizeZero);
+ std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
// We only assume exceptional states if they are definitely true; if the
// state is under-constrained, assume regular realloc behavior.
bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
@@ -1711,7 +1882,7 @@
// 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);
+ SVal RetVal = State->getSVal(CE, LCtx);
SymbolRef ToPtr = RetVal.getAsSymbol();
if (!FromPtr || !ToPtr)
return nullptr;
@@ -1731,7 +1902,7 @@
// Default behavior.
if (ProgramStateRef stateFree =
- FreeMemAux(C, CE, state, 0, false, ReleasedAllocated)) {
+ FreeMemAux(C, CE, State, 0, false, ReleasedAllocated)) {
ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
UnknownVal(), stateFree);
@@ -1755,20 +1926,23 @@
return nullptr;
}
-ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE){
+ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,
+ ProgramStateRef State) {
+ if (!State)
+ return nullptr;
+
if (CE->getNumArgs() < 2)
return nullptr;
- ProgramStateRef state = C.getState();
SValBuilder &svalBuilder = C.getSValBuilder();
const LocationContext *LCtx = C.getLocationContext();
- SVal count = state->getSVal(CE->getArg(0), LCtx);
- SVal elementSize = state->getSVal(CE->getArg(1), LCtx);
- SVal TotalSize = svalBuilder.evalBinOp(state, BO_Mul, count, elementSize,
+ SVal count = State->getSVal(CE->getArg(0), LCtx);
+ SVal elementSize = State->getSVal(CE->getArg(1), LCtx);
+ SVal TotalSize = svalBuilder.evalBinOp(State, BO_Mul, count, elementSize,
svalBuilder.getContext().getSizeType());
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
- return MallocMemAux(C, CE, TotalSize, zeroVal, state);
+ return MallocMemAux(C, CE, TotalSize, zeroVal, State);
}
LeakInfo
Index: test/Analysis/malloc-annotations.c
===================================================================
--- test/Analysis/malloc-annotations.c
+++ test/Analysis/malloc-annotations.c
@@ -37,13 +37,14 @@
void f2_realloc_0() {
int *p = malloc(12);
- realloc(p,0);
- realloc(p,0); // expected-warning{{Attempt to free released memory}}
+ realloc(p, 12);
+ realloc(p, 12); // expected-warning{{Attempt to free released memory}}
}
void f2_realloc_1() {
int *p = malloc(12);
- int *q = realloc(p,0); // no-warning
+ int *q = realloc(p, 12); // no-warning
+ free(q);
}
// ownership attributes tests
@@ -181,7 +182,7 @@
if (!p)
return; // no-warning
else
- realloc(p,0);
+ realloc(p,0); // expected-warning{{Call to 'realloc()' has an allocation size of 0 bytes}}
}
@@ -203,8 +204,9 @@
void f7_realloc() {
char *x = (char*) malloc(4);
- realloc(x,0);
+ char *y = realloc(x, 4);
x[0] = 'a'; // expected-warning{{Use of memory after it is freed}}
+ free(y);
}
void PR6123() {
Index: test/Analysis/malloc.c
===================================================================
--- test/Analysis/malloc.c
+++ test/Analysis/malloc.c
@@ -5,6 +5,7 @@
void clang_analyzer_eval(int);
typedef __typeof(sizeof(int)) size_t;
+void *alloca(size_t);
void *malloc(size_t);
void *valloc(size_t);
void free(void *);
@@ -32,13 +33,13 @@
void f2_realloc_0() {
int *p = malloc(12);
- realloc(p,0);
- realloc(p,0); // expected-warning{{Attempt to free released memory}}
+ realloc(p, 12);
+ realloc(p, 12); // expected-warning{{Attempt to free released memory}}
}
void f2_realloc_1() {
int *p = malloc(12);
- int *q = realloc(p,0); // no-warning
+ int *q = realloc(p, 0); // expected-warning{{Call to 'realloc()' has an allocation size of 0 bytes}}
}
void reallocNotNullPtr(unsigned sizeIn) {
@@ -67,11 +68,15 @@
}
}
+// FIXME: Now unix.Malloc warns about 'zero size allocation' when see zero
+// allocation like realloc(p, 0);
+// Commented until we decide how zero size realloc should be handled.
+/*
void reallocSizeZero1() {
char *p = malloc(12);
char *r = realloc(p, 0);
if (!r) {
- free(p); // expected-warning {{Attempt to free released memory}}
+ free(p); // FIXME:expected-warning {{Attempt to free released memory}}
} else {
free(r);
}
@@ -81,19 +86,19 @@
char *p = malloc(12);
char *r = realloc(p, 0);
if (!r) {
- free(p); // expected-warning {{Attempt to free released memory}}
+ free(p); // FIXME:expected-warning {{Attempt to free released memory}}
} else {
free(r);
}
- free(p); // expected-warning {{Attempt to free released memory}}
+ free(p); // FIXME:expected-warning {{Attempt to free released memory}}
}
void reallocSizeZero3() {
char *p = malloc(12);
char *r = realloc(p, 0);
free(r);
}
-
+*/
void reallocSizeZero4() {
char *r = realloc(0, 0);
free(r);
@@ -229,7 +234,7 @@
if (!p)
return; // no-warning
else
- realloc(p,0);
+ realloc(p,0); // expected-warning{{Call to 'realloc()' has an allocation size of 0 bytes}}
}
@@ -257,7 +262,7 @@
void f7_realloc() {
char *x = (char*) malloc(4);
- realloc(x,0);
+ realloc(x, 4);
x[0] = 'a'; // expected-warning{{Use of memory after it is freed}}
}
@@ -949,6 +954,79 @@
}
// ----------------------------------------------------------------------------
+// Test zero-sized allocations.
+void testMallocZero() {
+ char* foo = malloc(0); // expected-warning{{Call to 'malloc()' has an allocation size of 0 bytes}}
+ free(foo);
+}
+
+void testMallocZeroNoWarn(size_t size) {
+ char* foo = malloc(size); // no-warning
+ free(foo);
+}
+
+void testCalloc1Zero(void) {
+ char *foo = calloc(0, 42); // expected-warning{{Call to 'calloc()' has an allocation size of 0 bytes}}
+ free(foo);
+}
+
+void testCalloc2Zero(void) {
+ char *foo = calloc(42, 0); // expected-warning{{Call to 'calloc()' has an allocation size of 0 bytes}}
+ free(foo);
+}
+
+void testCallocZeroNoWarn(size_t nmemb, size_t size) {
+ char *foo = calloc(nmemb, size); // no-warning
+ free(foo);
+}
+
+void testReallocZero(char *ptr) {
+ char *foo = realloc(ptr, 0); // expected-warning{{Call to 'realloc()' has an allocation size of 0 bytes}}
+ free(foo);
+}
+
+void testReallocZeroNoWarn(char *ptr, size_t size) {
+ char *foo = realloc(ptr, size); // no-warning
+ free(foo);
+}
+
+void testReallocfZero(char *ptr) {
+ char *foo = reallocf(ptr, 0); // expected-warning{{Call to 'reallocf()' has an allocation size of 0 bytes}}
+ free(foo);
+}
+
+void testReallocfZeroNoWarn(char *ptr, size_t size) {
+ char *foo = reallocf(ptr, size); // no-warning
+ free(foo);
+}
+
+void testAllocaZero() {
+ char *foo = alloca(0); // expected-warning{{Call to 'alloca()' has an allocation size of 0 bytes}}
+}
+
+void testAllocaZeroNoWarn(size_t sz) {
+ char *foo = alloca(sz); // no-warning
+}
+
+void testBuiltinAllocaZero() {
+ char *foo2 = __builtin_alloca(0); // expected-warning{{Call to '__builtin_alloca()' has an allocation size of 0 bytes}}
+}
+
+void testBuiltinAllocaZeroNoWarn(size_t sz) {
+ char *foo2 = __builtin_alloca(sz); // no-warning
+}
+
+void testVallocZero() {
+ char *foo = valloc(0); // expected-warning{{Call to 'valloc()' has an allocation size of 0 bytes}}
+ free(foo);
+}
+
+void testVallocZeroNoWarn(size_t sz) {
+ char *foo = valloc(sz); // no-warning
+ free(foo);
+}
+
+// ----------------------------------------------------------------------------
// Test the system library functions to which the pointer can escape.
// This tests false positive suppression.
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits