メインコンテンツ

CERT C: Rule DCL38-C

フレキシブル配列メンバーの宣言時に正しい構文を使用する

説明

ルール定義

フレキシブル配列メンバーの宣言時に正しい構文を使用します。1

Polyspace 実装

ルール チェッカーは、"フレキシブル配列メンバー サイズの構文が正しくありません" をチェックします。

すべて展開する

問題

フレキシブル配列メンバー サイズの構文が正しくありませんは、標準 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 つのメンバーが含まれている必要があり、配列は構造体の最後のメンバーでなければなりません。

例 - サイズ 1 で定義されたフレキシブル配列メンバー
#include <stdlib.h>
  
struct flexArrayStruct {
  int num;
  int data[1]; //Noncompliant
};

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);
}

チェック情報

グループ: Rule 02.宣言と初期化 (DCL)

バージョン履歴

R2019a で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.