Search code examples
cmallocalignmentlanguage-lawyer

Since the result of malloc does not seem to be guaranteed to be aligned to anything, is it even usable?


I recently learned that dereferencing a pointer not aligned for a certain object (uint32_t* foo = (uint32_t*)7; *foo = 5;) is in fact undefined behaviour:

C11 section 6.2.8: Alignment of objects:

Complete object types have alignment requirements which place restrictions on the addresses at which objects of that type may be allocated. An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type: stricter alignment can be requested using the _Alignas keyword.

Ok, very interesting. But malloc does not seem to care at all about alignment:

7.22.3.4 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 value is indeterminate.

Returns

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

Therefore: Is there not a very real chance that doing something like the following invokes undefined behaviour?

uint32_t* a = malloc(10*sizeof(uint32_t));
*a = 7;

We have no guarantee that the return value of malloc is aligned to anything, after all.


Solution

  • You seem to have skipped a paragraph of the Standard just a tiny bit earlier than the part you quote regarding the malloc function. From this C17 Draft Standard – and it's much the same in C11 and other, later versions of the Standard (bold emphasis mine):

    7.22.3 Memory management functions

    1      The order and contiguity of storage allocated by successive calls to the aligned_alloc, calloc, malloc, and realloc functions is unspecified. 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). The lifetime of an allocated object extends from the allocation until the deallocation. Each such allocation shall yield a pointer to an object disjoint from any other object. The pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null pointer is returned. If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned to indicate an error, 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.

    So, the basic premise of your question is wrong and a pointer returned by a (successful) call to malloc will be usable for almost any type of object, in terms of its alignment requirements. The situation may be different for objects that have extended alignment requirements, in which case more specific allocation techniques should be used.