The 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 (188.8.131.52), 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.
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(&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
calloc, so the bytes are properly initialized. In our case all bytes have value
0, but any other proper initialization would do.
uint32_tis an exact width type and has no padding bits