问题
I am working to develop debug implementations of the four basic memory allocation routines malloc
, realloc
, calloc
, and free
(similar in operation to Electric Fence) to debug heap corruption on embedded systems which do not have the resources to run other memory debugging tools, or for which other tools do not exist (for instance, LynxOS 7.0 for PowerPC ships with GCC 4.6.3, and a proprietary implementation of glibc and libstdc++ which does not include the mtrace
family of functions).
The following is the source code for calloc, from calloc.c in GCC's libiberty.
PTR
calloc (size_t nelem, size_t elsize)
{
register PTR ptr;
if (nelem == 0 || elsize == 0)
nelem = elsize = 1;
ptr = malloc (nelem * elsize);
if (ptr) bzero (ptr, nelem * elsize);
return ptr;
}
Why are nelem
and elsize
both set equal to 1
if either equals 0
?
If I attempt to allocate 0
chunks of size n
or n
chunks with 0
size, wouldn't either case result in an aggregate allocation of 0
total bytes, and not 1
byte?
回答1:
Yes, this is just bad code, which is not unexpected from libiberty/gnulib/etc. As I understand it they already replace malloc
if malloc(0)
returns a null pointer rather than a unique pointer for each call, so I don't see any good reason for making calloc
pass 1 to malloc
instead of 0. Moreover, passing 1 breaks/undermines debugging tools like sanitizers that could tell you if you inadvertently dereferenced the pointer to a "zero-element array".
The code is also incredibly dangerous in that it does not check for overflow of the multiplication; any correct implementation of calloc
is required to do this.
TL;DR: this code is junk.
回答2:
Why does calloc allocate 1 byte if nelem or elsize == zero?
To reduce ambiguity.
calloc(0, x), calloc(x, 0), malloc(0)
, when successful, may return NULL
or a non-NULL
pointer. In both cases, the pointer may not be de-referenced without causing undefined behavior (UB).
When unsuccessful, a NULL
pointer is returned.
By insuring the allocation size is more than 0, there is no ambiguity when NULL
is returned - the allocation failed from this calloc()
.
Note, a better function would also detect product overflow.
if (nelem == 0 || elsize == 0) {
nelem = elsize = 1;
} else if (SIZE_MAX/nelem > elsize) {
return NULL; // Too much for this implementation
}
...
Further thought about Electric_Fence:
I'd expect the malloc(0)
of that project to also insure that 0 bytes are not allocated. Yet simply calling ptr = malloc (0); if (ptr) bzero (ptr, 0);
would not zero that 1 byte allocation. if (nelem == 0 || elsize == 0) nelem = elsize = 1;
makes certain the allocation is at least 1 byte and that allocation is zeroed.
来源:https://stackoverflow.com/questions/58442295/why-does-calloc-allocate-1-byte-if-nelem-or-elsize-zero