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

ARR36-C. 異なる配列を指す2つのポインタに対して減算や比較を行わない

ポインタ同士の減算を行う場合、両方が同じ配列オブジェクトの要素、または配列オブジェクトの最後の要素を 1 つ超えた位置、を指している必要がある(C 言語規格 [ISO/IEC 9899:2011] のセクション 6.5.6)。減算の結果は、2 つの配列要素の添字の差分となる。そうでない場合は、操作の結果、未定義動作が発生する(附属書 J 「未定義の動作」の 48 を参照)。このような制限が存在する理由は、C では、ポインタの減算結果はバイト数ではなく、2 つのポインタ間のオブジェクト数を意味するからである。

同様に、ポインタの比較では、関係演算子 <<=>=、および > を使い、ポインタ同士の相対的な位置を比較することができる。異なる配列の要素を指すポインタに対して減算や比較を行うと、未定義の動作が発生する(附属書 J 「未定義の動作」の 48 および 53 を参照)。

等価演算子 == および != を使用したポインタ比較は、ポインタがいずれも NULL であるか、同じオブジェクトを指すか、配列オブジェクトの最後の要素を一つ超えたところを指すか、関数を指すかに関わらず、明確に定義されたセマンティクスを持つ。

適切に型変換された、単一の 構造体オブジェクト内の 2 つのメンバポインタの減算または比較は行ってもよい。これは、オブジェクトはすべて unsigned char の配列として扱うことができるためである。ただしこれを行う際には、構造体の境界調整と詰め物の影響を考慮する必要がある。

違反コード

下記のコード例では、ポインタ減算を使って、nums 配列に残されている未使用の要素の数を調べている。

enum { SIZE = 32 };
 
void func(void) {
  int nums[SIZE];
  char *c_str[SIZE];
  int *next_num_ptr = nums;
  int free_bytes;
 
/* 配列にデータを入れるごとに next_num_ptr をインクリメントする */
 
  free_bytes = c_str - (char **)next_num_ptr;
}

この例では2つの間違った想定をしている。第一に、numsc_str 配列がメモリ内で必ず隣接していると想定している。第二に、free_bytes が利用可能なバイト数を表すと想定している。減算の結果として返されるのは、next_num_ptrc_str の間の要素数である。

適合コード

下記の解決法では、未使用の要素数をカウンタとして保持し、配列操作ごとに管理している。また、ポインタ演算ではバイト数ではなく未使用の要素数を計算している。こうすることで、計算間違いが発生することを防止している。

enum { SIZE = 32 };
 
void func(void) {
  int nums[SIZE];
  int *next_num_ptr = nums;
  int free_bytes;
 
  /* 配列にデータを入れるごとに next_num_ptr をインクリメントする */
 
  free_bytes = (&(nums[SIZE]) - next_num_ptr) * sizeof(int);
}
例外

ARR36-EX1: 同じオブジェクト内の 2 つのポインタは比較してもよい。
ARR36-EX2: 同じオブジェクト内の 2 つのchar へのポインタは減算してもよい。  

リスク評価

ルール

深刻度

可能性

修正コスト

優先度

レベル

ARR36-C

P8

L2

自動検出

ツール

バージョン

チェッカー

説明

LDRA tool suite

V. 8.5.4

438 S

実装済み

PRQA QA-C 8.1

0487
2771

実装済み
関連する脆弱性
関連するガイドライン
CERT C++ Secure Coding Standard ARR36-CPP. Do not subtract or compare two pointers or iterators that do not refer to the same array or container
MITRE CWE CWE-469, Use of pointer subtraction to determine size
参考資料
[Banahan 2003] Section 5.3, "Pointers"
Section 5.7, "Expressions Involving Pointers"
翻訳元

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

ARR36-C. Do not subtract or compare two pointers that do not refer to the same array (revision 59)

Top へ

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