What is the alignment requirement of malloc(1)

170 views Asked by At

I have heard that a successful call to malloc() returns a pointer suitably aligned for any type. Yet it seems useless and wasteful to require malloc(1) to return a pointer aligned for a larger value than 1 since no object larger than char can be stored into the block.

What is the alignment requirement for malloc(1), malloc(2), etc.

If the alignment is larger than the allocated size, what is the rationale for such a requirement?

1

There are 1 answers

10
chqrlie On BEST ANSWER

The definition of the malloc function in the C Standard is terse and does not specify anything regarding alignment. The abstract from the C23 Standard below is substantially similar to previous editions with only a chapter number change:

7.24.3.6 The malloc function

Synopsis

#include <stdlib.h>
void *malloc(size_t size);

Description

The malloc function allocates space for an object whose size is specified by size and whose representation is indeterminate.

Returns

The malloc function returns either a null pointer or a pointer to the allocated space.

Regarding the block alignment requirement, up until C17, this was specified at the beginning of the parent chapter:

7.22.3 Memory management functions
[...]
The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated).

This meant that malloc(1) must be correctly aligned for all fundamental types such as int, long, long long, etc. and is somewhat ambiguous about accessing such objects in the space allocated.

Reported as a defect, this problem was discussed and the text was amended in C23 to relax this requirement and clarify this ambiguity (emphasis mine):

7.24.3 Memory management functions
[...]
The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and size less than or equal to the size requested. It may then be used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated).

This amendment is welcome: from C23 on, malloc(1) has no alignment requirement and successive calls to malloc(1) may return successive addresses in a packed array of bytes. Similarly, malloc(2) is no longer required be be suitably aligned for objects of size greater than 2. malloc(3) will be suitably aligned for 2 byte objects such as short on most architectures, etc.

This may cause problems for packages that take advantage of the original alignment requirement to store tags in the low order bits of object pointers returned by malloc(). The size passed to malloc on such systems must be greater than or equal to 2n where n is the number of bits in the tag, typically limited to 3 or 4. A better solution is to use aligned_malloc() where the alignment requirement can be specified and tested.

Note also that the alignment requirement for the block returned by calloc(4, 1) is 4, as the allocated size is the product of the arguments, the first being the number of elements to allocate space for, the second being the element size. Programmers hence do not need to be aware of the arguments' precise semantics. Note that nelems and size are passed in a different order in other C library functions that take such arguments, such as fread(), fwrite(), qsort() and bsearch().

realloc() follows the same requirements: reducing the size of a block may produce a different pointer with a weaker alignment.