PORTING.STORAGE.STRUCT

不明確なストレージ構造型の結果

PORTING チェッカーは、異なるコンパイラ内で特定の実装詳細に依存する可能性があるコードを識別します。PORTING.STORAGE.STRUCT チェッカーは、構造内の要素のバイト位置が配置属性およびパッケージ属性により異なる可能性がある状況を検出します。

脆弱性とリスク

このチェッカーは、さまざまなメモリレイアウト指示がデータ構造に適用される状況を警告するので、新しいプラットフォームへのアプローチを適切に計画することができます。

コンパイラやターゲットプラットフォームで使用する配置によっては、構造内のフィールドの全体のサイズおよび値がかなり異なる場合があります。構造内の要素のバイト位置が配置属性およびパッケージ属性により異なるため、移植されるコードで考慮することが重要です。たとえば、フィールド値がストレージから読み取られ、ファイルで使用またはネットワーク上で送信される場合に、これらのレイアウト指示はコンパイラの動作に大きな影響を与えます。

脆弱なコード例

コピー
struct my_struct {
    int16_t flag1;
    int32_t value;
    int16_t flag2;
};

この例では、2 番目の (値) と3 番目の (フラグ 2) フィールドの全体のサイズとオフセットは、コンパイラオプションやターゲットのプラットフォームによって異なる場合があります。たとえば、デフォルトの配置は次のとおりです。

コピー
 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

ただし、'packed struct' コンパイラオプションや pragma が使用されている場合は、次のように異なる結果となります。

コピー
offset of 'flag1' = 0
offset of 'value' = 2
offset of 'flag2' = 6
size of 'my_struct' = 8

この配置では、データ構造のファイルまたはネットワークソケットへのシリアル化のプロセスにより、デフォルトの配置とはまったく異なる結果となります。

修正されたコード例

問題を修正する方法の 1 つに、'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;
   };