メインコンテンツ

AUTOSAR C++14 Rule M5-0-16

A pointer operand and any pointer resulting from pointer arithmetic using that operand shall both address elements of the same array

R2021a 以降

説明

ルール定義

A pointer operand and any pointer resulting from pointer arithmetic using that operand shall both address elements of the same array.

根拠

配列要素へのポインターを使用するポインター算術演算の結果が次のいずれも指していない場合、動作は未定義になります。

  • 配列の要素。

  • 配列の最後の要素を超えた位置。次に例を示します。

    int arr[3];
    int* res;
    res = arr+3; // res points to one beyond arr

ルールは次の演算に適用されます。ptr は配列要素へのポインターで、int_exp は整数式です。

  • ptr + int_exp

  • int_exp + ptr

  • ptr - int_exp

  • ptr + +

  • ++ptr

  • --ptr

  • ptr--

  • ptr [ int_exp ]

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 は、この演算にフラグを設定しません。

チェッカーの拡張

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

トラブルシューティング

ルール違反が想定されるものの、Polyspace から報告されない場合は、コーディング規約違反が想定どおりに表示されない理由の診断を参照してください。

すべて展開する

void f_incr(int* x)
{
    int* ptr_to_one = x;
    ++ptr_to_one;  // Compliant
}

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

int main()
{

    int arr_one = 1; // Equivalent to array of one element
    f_incr(&arr_one);

    int arr[3] {};
    f1(arr);

    struct {
        char elem1[10];
        char elem2[10];
    } myStruct;

    char* ptr_to_struct = &myStruct.elem1[11]; // Compliant
    ptr_to_struct = &myStruct.elem2[11]; //Non-compliant

    int tab[3] {1, 2, 3};
    int* ptr =  &tab[2];
    int res = tab[2];
    ++ptr; // Compliant
    res = *ptr; //Non-compliant

    return 0;
}

この例では以下のようになります。

  • f_incr() 内の ptr_to_one のインクリメントはルールに準拠しています。この演算の結果は配列 x の最後の要素を超えた位置を指すポインターになるからです。f_incr() に渡される整数は 1 要素の配列と等価です。

  • f1() 内のポインター パラメーター a1 に対する演算はルールに準拠しています。このポインターは配列 arr を指しているからです。

  • ptr_to_struct の 1 番目の代入はルールに準拠しています。elem1[11] はまだ myStruct の内部だからです。ptr_to_struct の 2 番目の代入はルールに準拠していません。演算結果は myStruct の内部も myStruct の最後の要素を超えた位置も指していないからです。

  • ptr のインクリメントはルールに準拠しています。演算結果は tab の最後の要素を超えた位置を指しているからです。次の行の ptr のデリファレンスはルールに準拠していません。

チェック情報

グループ:
カテゴリ: Required、Automated

バージョン履歴

R2021a で導入

すべて展開する