PORTING.STORAGE.STRUCT

不确定的存储器结构结果

PORTING 检查器会标识那些可能依赖于不同编译器中特定实施细则的代码。PORTING.STORAGE.STRUCT 检查器检测那些结构中元素的字节位置可能因对齐和封装属性的变化而不同的情况。

漏洞与风险

当数据结构应用了不同的内存布局指令时,该检查器会警告您,以便您可以针对新平台来计划适当的方法。

根据编译器或目标平台使用的对齐,结构中字段的总体大小和值可能大不相同。结构中元素的字节位置取决于对齐和封装属性,因此请务必将它们纳入到移植代码的考量中。例如,当字段值读取自存储器并用于文件中或发送到网络上时,这些布局指令可能对编译器的行为产生显著影响。

漏洞代码示例

复制
struct my_struct {
    int16_t flag1;
    int32_t value;
    int16_t flag2;
};

在本示例中,第二个 (value) 和第三个 (flag2) 字段的总体大小和偏移可能会有所不同,具体取决于编译器选项和目标平台。例如,默认对齐为:

复制
 offset of 'flag1' = 0
 offset of 'value' = 4(按 32 位边界对齐)
 offset of 'flag2' = 8(按 32 位边界对齐)
 size of 'my_struct' = 12

但是,如果使用了 'packed struct' 编译器选项或编译指示,结果将不同:

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

利用该对齐,将数据结构串行化到文件或网络套接字的进程将产生与默认对齐完全不同的结果。

修正代码示例

修复该问题的一种方法是重新排序“struct”字段:

复制
   strut my_struct {
     int16_t flag1;
     int16_t flag2;
     int32_t value;
   };

如此一来,无论对齐和封装属性如何变化,字段的偏移和结构的总体大小将始终相同。

另一种选项是针对字段使用较大的类型,这样它们就不需要进行任何对齐或填充操作:

复制
   struct my_struct {
     int32_t flag1;
     int32_t value;
     int32_t field2;
   };