Conversion between pointer types produces incorrectly aligned result
suggest changeThe following might have undefined behavior due to incorrect pointer alignment:
char *memory_block = calloc(sizeof(uint32_t) + 1, 1);
uint32_t *intptr = (uint32_t*)(memory_block + 1); /* possible undefined behavior */
uint32_t mvalue = *intptr;
The undefined behavior happens as the pointer is converted. According to C11, if a conversion between two pointer types produces a result that is incorrectly aligned (6.3.2.3), the behavior is undefined. Here an uint32_t
could require alignment of 2 or 4 for example.
calloc
on the other hand is required to return a pointer that is suitably aligned for any object type; thus memory_block
is properly aligned to contain an uint32_t
in its initial part. Then, on a system where uint32_t
has required alignment of 2 or 4, memory_block + 1
will be an odd address and thus not properly aligned.
Observe that the C standard requests that already the cast operation is undefined. This is imposed because on platforms where addresses are segmented, the byte address memory_block + 1
may not even have a proper representation as an integer pointer.
Casting char *
to pointers to other types without any concern to alignment requirements is sometimes incorrectly used for decoding packed structures such as file headers or network packets.
You can avoid the undefined behavior arising from misaligned pointer conversion by using memcpy
:
memcpy(&mvalue, memory_block + 1, sizeof mvalue);
Here no pointer conversion to uint32_t*
takes place and the bytes are copied one by one.
This copy operation for our example only leads to valid value of mvalue
because:
- We used
calloc
, so the bytes are properly initialized. In our case all bytes have value0
, but any other proper initialization would do. uint32_t
is an exact width type and has no padding bits- Any arbitrary bit pattern is a valid representation for any unsigned type.