PORTING.STORAGE.STRUCT

Uncertain storage structure results

The PORTING checkers identify code that might rely on specific implementation details in different compilers. The PORTING.STORAGE.STRUCT checker detects situations in which the byte position of elements in a structure could differ, depending on alignment and packing attributes.

Vulnerability and risk

This checker warns you of situations in which the use of the various memory layout directives are applied to data structures, so that you can plan your approach to the new platform appropriately.

Depending on the alignment used by the compiler or target platform, the overall size and value of the fields in the structure can be quite different. The byte position of elements in the structure depends on alignment and packing attributes, so it's important to take that into account in the ported code. For example, these layout directives can significantly affect the behavior of the compiler when the field values are read from storage and used in files or sent out on the network.

Vulnerable code examples

Copy
struct my_struct {
    int16_t flag1;
    int32_t value;
    int16_t flag2;
};

In this example, the overall size and offset of the second (value) and third (flag2) fields could be different, depending on the compiler options and target platform. For example, the default alignment would be:

Copy
 offset of 'flag1' = 0
 offset of 'value' = 4 (aligned by 32-bit boundary)
 offset of 'flag2' = 8 (aligned by 32-bit boundary)
 size of 'my_struct' = 12

However, if the 'packed struct' compiler option or pragma is used, the result is different:

Copy
offset of 'flag1' = 0
offset of 'value' = 2
offset of 'flag2' = 6
size of 'my_struct' = 8

With this alignment, the process of serializing the data structure to a file or network socket would produce totally different results than in the default alignment.

Fixed code examples

One way of fixing the problem is to re-order the 'struct' fields:

Copy
   strut my_struct {
     int16_t flag1;
     int16_t flag2;
     int32_t value;
   };

This way, the offset of the fields and the overall size of the structure would always be the same, regardless of alignment and packing attributes.

Another option is to use larger types for the fields, so that they don't need any alignment or padding:

Copy
   struct my_struct {
     int32_t flag1;
     int32_t value;
     int32_t field2;
   };