メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

MISRA C:2012 Rule 18.1

A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand

説明

ルール定義

A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand 1 .

根拠

無効な配列の添字を使用するとプログラムの誤動作につながる可能性があります。実行時に派生した配列の添字は、手動によるレビューまたは静的解析で容易にチェックできないため特に問題となります。

C 標準に従うと、配列の終わりを超えた要素を指すポインターのデリファレンスは未定義の動作を発生させるため、準拠しません。

ポインター T* をポインター char* または unsigned char* に変換する場合、変換後のポインターの範囲は sizeof(T) と見なされます。たとえば次のコードでは、arrayunsigned char 型のオブジェクト 4 を収容します。

unsigned int obj = 42;
unsigned char *array = (unsigned char*) &obj;
unsigned char small_obj = array[3];

Polyspace 実装

Polyspace® は、次の場合にこのルールの違反を報告します。

  • 配列へのアクセス中に配列のインデックスが範囲 [0...array_size-1] から外れた場合。

  • ポインターがその範囲外でデリファレンスされた場合。

Polyspace は、このルールに対する違反をチェックする際に次の要因を考慮します。

  • 配列の一部ではない単一のオブジェクトは、1 要素の配列と見なされます。たとえば、このコード例では arr_one は 1 要素の配列と等価です。Polyspace はポインター ptr_to_one のインクリメントにフラグを設定しません。arr_one の最後の要素を超えた位置を指しているからです。

    void f_incr(int* x){
    	int* ptr_to_one = x;
        ++ptr_to_one;  // Compliant
    }
    
    void func(){
    	int arr_one=1; // Equivalent to array of one element
    	f_incr(&arr_one);
    }

  • Polyspace は、ポインターが配列を指している場合、ポインター算術演算でのポインター パラメーターの使用にフラグを設定しません。たとえば、このコード スニペットで f1 に配列を渡した場合、f1&a1[2] はルールに準拠しています。

    void f1( int* const a1){
           int* b= &a1[2]; // Compliant
    }
    void f2(){
    	int arr[3] {};
    	f1(arr);	
    }

  • 複数の要素を含む構造体で、要素に対するポインターが構造体に割り当てられたメモリ内を指していたり、構造体の最後の要素を超えた位置を指していたりする場合、Polyspace は、別の要素を指すポインターとなる要素のポインターに対する算術演算の結果にフラグを設定しません。

    たとえばこのコード スニペットでは、ptr_to_struct への代入はルールに準拠しています。myStruct.elem1 の外部を指していますが、それでも myStruct の内部にとどまっているからです。最終結果としてのアドレスが構造体に割り当てられたメモリの内部であったとしても、要素の次元より大きいインデックスを使用して要素の内容にアクセスすることはルールに準拠していません。

    void func(){
    	struct {
    		char elem1[10];
    		char elem2[10];
    	} myStruct;
    	
    	char* ptr_to_struct = &myStruct.elem1[11]; //Compliant
          // Address of myStruct.elem1[11] is inside myStruct
          char val_to_struct = myStruct.elem1[11]; // Non-compliant
    }

  • 多次元配列では、Polyspace は、部分配列の要素へのアクセスに部分配列の次元より大きいインデックスを使用している箇所にフラグを設定します。Polyspace は、アドレスがトップレベルの配列に割り当てられたメモリの内部である場合、同じ部分配列のアドレスの代入にはフラグを設定しません。

    たとえばこのコード スニペットでは、ポインター ptr_to_arr への代入はルールに準拠しています。このポインターは multi_arr に割り当てられたメモリの内部のアドレスを指しているからです。変数 arr_val への代入はルールに準拠していません。部分配列要素へのアクセスに使用されるインデックス (3) が部分配列の次元 (2) よりも大きいからです。

    void func(){
    	int multi_arr[5][2];
    
          // Assigned memory is inside top level array
    	int* ptr_to_arr = &multi_arr[2][3]; //Compliant
    
    	// Use of index 3 with subarray of size 2
    	int arr_val = multi_arr[2][3]; // Non-compliant
    }

  • Polyspace は、ポインターが配列の最後の要素を超えた位置を指す場合、そのポインターのデリファレンスにフラグを設定します。たとえばこのコード スニペットでは、ptr の代入はルールに準拠していますが、ptr のデリファレンスは準拠していません。tab+3 は tab の最後の要素を超えた位置です。

    void derefPtr(){
    	int tab[3] {};
    	int* ptr = tab+3; //Compliant
    	int res = *(tab+3); // Non-compliant
    }

  • ポインター算術演算の結果が nullptr になる場合、Polyspace はこのチェッカーを起動しません。たとえば、次のコードを考えます。

    void g(int *p);
    
    void add(int* p, int n) {
        g(p + n);   //Compliant}
    
    void foo() {
        add(nullptr, 0);
        
    }
    add() でのポインター演算の結果は nullptr になります。Polyspace は、この演算にフラグを設定しません。

  • Polyspace がポインターまたは配列へのアクセスに対してこのルールの違反を報告する場合、それ以降のそのポインターまたは配列へのアクセスについては違反が報告されなくなります。たとえば、Polyspace は pointer2array への最初のインクリメントに対してこのルールの違反を報告します。この違反を修正すると、それ以降の範囲外のアクセスも修正できます。報告された問題を修正した後に範囲外のアクセスが残っている場合、Polyspace はそれらを違反として報告します。

    #include <stdint.h>
    int32_t data = 0;
    
    int32_t simple_array[ 10 ] = { 0 };
    
    void Func(void) {
    	int32_t *pointer2array = &simple_array[ 10 ];
    	pointer2array++;         /* Noncompliant - accessing array out of bound */
    	data = *pointer2array;   /* Noncompliant - pointer out of bounds after increment*/
    	pointer2array++;         /* Violation no longer reported for out of bound access*/
    }

チェッカーの拡張

入力値が不明であり、入力のサブセットのみがエラーの原因として考えられる場合、既定の Bug Finder 解析ではこのルールに対する違反が報告されない場合があります。特定のシステム入力値を原因とする違反の有無をチェックするには、より厳密な Bug Finder 解析を実行してください。特定のシステム入力値から欠陥を見つけるための Bug Finder チェッカーの拡張を参照してください。

トラブルシューティング

ルール違反を想定していてもその違反が表示されない場合、コーディング規約違反が想定どおりに表示されない理由の診断を参照します。

すべて展開する

この例では、ポインター pointer は最初に、バッファー array の末尾より後の 1 つの要素を指しています。末尾より後の要素を指すことは、C 標準では許可されますが、この場所をデリファレンスすると未定義の動作が発生するため、このルールには準拠していません。コードが *pointer および *(pointer++) をデリファレンスする場合、Polyspace は違反を報告します。

void foo ( void )
{
  int array[10] = {0};
  int* pointer = &array[10];
  int data1 = *(pointer++); /* Noncompliant*/
  int data2 = *(pointer); /* Noncompliant*/
  int data3 = *(pointer--); /* Compliant*/

}

チェック情報

グループ: ポインターと配列
カテゴリ: 必要
AGC カテゴリ: 必要

バージョン履歴

すべて展開する


1 All MISRA coding rules and directives are © Copyright The MISRA Consortium Limited 2021.

The MISRA coding standards referenced in the Polyspace Bug Finder™ documentation are from the following MISRA standards:

  • MISRA C:2004

  • MISRA C:2012

  • MISRA C:2023

  • MISRA C++:2008

  • MISRA C++:2023

MISRA and MISRA C are registered trademarks of The MISRA Consortium Limited 2021.