メインコンテンツ

フレキシブル配列メンバー サイズの構文が正しくありません

サイズ 0 または 1 で定義されたフレキシブル配列メンバー

説明

この欠陥は、標準 C 構文を使用せずに、フレキシブル配列メンバーをもつ構造体を定義した場合に発生します。

C99 以降、サイズを指定せずにフレキシブル配列メンバーを定義できます。たとえば、次の例における desc はフレキシブル配列メンバーです。

struct record {
    size_t len;
    double desc[]; 
};
C99 よりも以前は、コンパイラ固有のメソッドを使用してフレキシブル配列を定義していたことがありました。たとえば、次のようにサイズ 1 または 0 の配列を使用しました。
struct record {
    size_t len;
    double desc[0]; 
};
この使用法は C99 以降の C 標準には準拠していません。

リスク

サイズ 0 または 1 を使用してフレキシブル配列メンバーを定義する場合、実装はコンパイラに依存します。この構文を認識しないコンパイラでは、サイズ 1 の int 配列は 1 つの int 変数のバッファーをもちます。このバッファーを超えて書き込もうとすると、範囲外の配列アクセスに起因する問題が生じる可能性があります。

標準 C 構文を使用してフレキシブル配列メンバーを定義している場合、実装は規格に準拠するすべてのコンパイラ間で移植可能になります。

修正方法

フレキシブル配列メンバーを構造体に実装するには、サイズ指定なしの配列を定義します。構造体にはその配列以外に 1 つのメンバーが含まれている必要があり、配列は構造体の最後のメンバーでなければなりません。

すべて展開する

#include <stdlib.h>
  
struct flexArrayStruct {
  int num;
  int data[1];
};

unsigned int max_size = 100;
 
void func(unsigned int array_size) {
  if(array_size<= 0 || array_size > max_size)  
      exit(1);
  /* Space is allocated for the struct */
  struct flexArrayStruct *structP
    = (struct flexArrayStruct *)
     malloc(sizeof(struct flexArrayStruct)
          + sizeof(int) * (array_size - 1));
  if (structP == NULL) {
    /* Handle malloc failure */
    exit(2);
  }
   
  structP->num = array_size;
 
  /*
   * Access data[] as if it had been allocated
   * as data[array_size].
   */
  for (unsigned int i = 0; i < array_size; ++i) {
    structP->data[i] = 1;
  }
  
  free(structP);
}

この例では、フレキシブル配列メンバー data はサイズ値 1 で定義されています。この構文を認識しないコンパイラは、data をサイズ 1 の配列として扱います。ステートメント structP->data[i] = 1; は、最初の配列メンバーを越えて data に書き込むことができ、範囲外の配列の問題を引き起こす可能性があります。

修正 — 標準 C 構文を使用してフレキシブル配列を定義

サイズを指定せずにフレキシブル配列メンバーを定義します。

#include <stdlib.h>
  
struct flexArrayStruct{
  int num;
  int data[];
};

unsigned int max_size = 100;
 
void func(unsigned int array_size) {
  if(array_size<=0 || array_size > max_size)  
      exit(1);
  
  /* Allocate space for structure */
  struct flexArrayStruct *structP
    = (struct flexArrayStruct *)
    malloc(sizeof(struct flexArrayStruct)
         + sizeof(int) * array_size);
         
  if (structP == NULL) {
    /* Handle malloc failure */
    exit(2);
  }
 
  structP->num = array_size;
 
  /*
   * Access data[] as if it had been allocated
   * as data[array_size].
   */
  for (unsigned int i = 0; i < array_size; ++i) {
    structP->data[i] = 1;
  }
  
  free(structP);
}

結果情報

グループ: 適切な手法
言語: C (オプション -c-version c90 で示される C90 コードに対して解析が実行された場合、チェッカーは無効)
既定値: オフ
コマンド ライン構文: FLEXIBLE_ARRAY_MEMBER_INCORRECT_SIZE
影響度: Low

バージョン履歴

R2018b で導入