C Language Undefined behavior Conversion between pointer types produces incorrectly aligned result


Example

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 (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 value 0, 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.