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\n", 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\n", 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.