JPCERT コーディネーションセンター

ARR37-C. 配列以外のオブジェクトを指すポインタに対して整数の加算や減算を行わない

ポインタに対する算術演算は、そのポインタが配列オブジェクトの要素を指す場合にのみ適切な操作である。

C 言語規格 [ISO/IEC 9899:2011] のセクション 6.5.6 には、ポインタ演算について次のように記されている。

ポインタに対して整数型の式が加算または減算されると、結果の型は、ポインタの型となる。ポインタが配列オブジェクトの要素を指しており、配列に十分な大きさがある場合、結果は、元の要素を起点としたとき、結果の配列要素と元の配列要素の添字の差が整数式と等しくなるようなオフセット位置にある要素を指す。

違反コード

下記の違反コード例では、プログラマはポインタ算術演算を使って構造体の要素にアクセスしようとしている。構造体内のフィールドがメモリ上に連続して配置されている保証はないため、これは危険な操作である。

struct numbers {
  short num_a;
  short num_b;
  /* . . . */
  short num_z;
};

int sum_numbers(const struct numbers *numb){
  int total = 0;
  const short *numb_ptr;

  for (numb_ptr = &numb->num_a;
       numb_ptr <= &numb->num_z;
       numb_ptr++)  {
    total += *(numb_ptr);
  }

  return total;
}

int main(void) {
  struct numbers my_numbers = { 1, 2, 3 };
  sum_numbers(&my_numbers);
  return 0;
}
適合コード

次に示すコードのように、-> 演算子を使って構造体の各要素を参照できる。

total = numb->num_a + numb->num_b + /* ...*/ numb->num_z;

ただしこの解決策は、違反コードを書いたプログラマがまさに避けようとした、非常に手間のかかるやり方である。

より良い解決法は、次のコードのように、配列を使用することである。

#include <stddef.h>
 
struct numbers {
  short num_a;
  short num_b;
  /* . . . */
  short num_z;
};

int sum_numbers(const short *numb, size_t dim) {
  int total = 0;
  const short *numb_ptr;

  for (numb_ptr = numb; numb_ptr < numb + dim; numb_ptr++) {
    total += *(numb_ptr);
  }

  return total;
}

int main(void) {
  short my_numbers[9] = { 1, 2, 3 };
  sum_numbers(
    my_numbers,
    sizeof(my_numbers)/sizeof(my_numbers[0])
  );
  return 0;
}

配列要素はメモリ内で連続していることが保証されているため、この解決法は可搬性に優れる。

例外

ARR37-EX0: メモリ上の配列ではないオブジェクトは、ある要素の配列であるとみなすことができる。そのようなポインタに1を足すと配列の終端を1つ超えた要素を指すポインタが、1を引くと元のポインタが得られる。この性質を利用して次のようなコードを書くことができる。

#include <stdlib.h>
#include <string.h>
 
struct s {
  char *str;
  /* その他のフィールド */
};
 
struct s *create_s(const char *str) {
  struct s *ret;
  size_t len = strlen(str) + 1;
   
  ret = (struct s *)malloc(sizeof(struct s) + len);
  if (ret != NULL) {
    ret->str = (char *)(ret + 1);
    memcpy(ret + 1, str, len);
  }
  return ret;
}
リスク評価

ルール

深刻度

可能性

修正コスト

優先度

レベル

ARR37-C

P8

L2

自動検出

ツール

バージョン

チェッカー

説明

Compass/ROSE

 

 

 

関連するガイドライン
CERT C++ Secure Coding Standard ARR37-CPP. Do not add or subtract an integer to a pointer to a non-array object
MITRE CWE CWE-469, Use of pointer subtraction to determine size
参考資料
[Banahan 2003] Section 5.3, "Pointers"
Section 5.7, "Expressions Involving Pointers"
[ISO/IEC 9899:2011] Subclause 6.5.6, "Additive Operators"
[VU#162289]  
翻訳元

これは以下のページを翻訳したものです。

ARR37-C. Do not add or subtract an integer to a pointer to a non-array object (revision 54)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter