Can calloc() allocate more than SIZE_MAX in total?
As the assertion "On select systems, calloc()
can allocate more than SIZE_MAX
total bytes whereas malloc()
is limited." came from a comment I posted, I will explain my rationale.
size_t
size_t
is some unsigned type of at least 16 bits.
size_t
which is the unsigned integer type of the result of the sizeof
operator; C11dr §7.19 2
"Its implementation-defined value shall be equal to or greater in magnitude
... than the corresponding value given below" ... limit of size_t
SIZE_MAX
... 65535 §7.20.3 2
sizeof
The sizeof
operator yields the size (in bytes) of its operand, which may be an
expression or the parenthesized name of a type. §6.5.3.4 2
calloc
void *calloc(size_t nmemb, size_t size);
The calloc
function allocates space for an array of nmemb
objects, each of whose size
is size. §7.22.3.2 2
Consider a situation where nmemb * size
well exceeds SIZE_MAX
.
size_t alot = SIZE_MAX/2;
double *p = calloc(alot, sizeof *p); // assume `double` is 8 bytes.
If calloc()
truly allocated nmemb * size
bytes and if p != NULL
is true, what spec did this violate?
The size of each element, (each object) is representable.
// Nicely reports the size of a pointer and an element.
printf("sizeof p:%zu, sizeof *p:%zu
", sizeof p, sizeof *p);
Each element can be accessed.
// Nicely reports the value of an `element` and the address of the element
for (size_t i = 0; i<alot; i++) {
printf("value a[%zu]:%g, address:%p
", i, p[i], (void*) &p[i]);
}
calloc()
details
"space for an array of nmemb
objects": This is certainly a key point of contention. Does the "allocates space for the array" require <= SIZE_MAX
? I found nothing in the C spec to require this limit and so conclude:
calloc()
may allocate more than SIZE_MAX
in total.
It is certainly uncommon for calloc()
with large arguments to return non-NULL
- compliant or not. Usually such allocations exceed memory available, so the issue is moot. The only case I've encountered was with the Huge memory model where size_t
was 16 bit and the object pointer was 32 bit.