メインコンテンツ

ISO/IEC TS 17961 [invptr]

範囲外のポインターまたは配列の添字の形成または使用

説明

ルール定義

範囲外のポインターまたは配列の添字の形成または使用。1

Polyspace 実装

このチェッカーは以下の問題をチェックします。

  • 配列が範囲外にアクセス

  • 範囲外にアクセスするポインター

チェッカーの拡張

入力値が不明であり、入力のサブセットのみが問題の原因となっている場合、Bug Finder が "配列が範囲外にアクセス" を検出しない場合があります。特定のシステム入力値を原因とする違反の有無をチェックするには、より厳密な Bug Finder 解析を実行してください。特定のシステム入力値から欠陥を見つけるための Bug Finder チェッカーの拡張を参照してください。

すべて展開する

問題

配列が範囲外にアクセスは、配列へのアクセス中に配列のインデックスが範囲 [0...array_size-1] を外れる場合に発生します。

リスク

配列の範囲外へのアクセスは未定義の動作です。予測不能な値を読み取ったり、許可されていない位置へのアクセスを試みてセグメンテーション違反が発生したりする可能性があります。

修正方法

修正方法は欠陥の根本原因によって異なります。たとえば、ループ内の配列にアクセスする際、次のいずれかの状況が発生したとします。

  • ループの上限が大きすぎる。

  • ループ インデックスより 1 小さい配列インデックスを使用せずに、ループ インデックスと同じ配列インデックスを使用している。

この問題を修正するには、ループの範囲または配列インデックスを変更する必要があります。

配列インデックスが配列範囲を超える別の理由として、事前に行われた符号付き整数から符号なし整数への変換が考えられます。この変換はインデックス値のラップ アラウンドを発生させる可能性があり、最終的に配列インデックスが配列範囲を超える原因になります。

多くの場合、結果の詳細には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して逆のトレースを行い、これまでの関連するイベントを確認できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈も参照してください。

以下の修正例を参照してください。

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 - 配列が範囲外にアクセス エラー
#include <stdio.h>

void fibonacci(void)
{
    int i;
    int fib[10];
 
    for (i = 0; i < 10; i++) 
       {
        if (i < 2) 
            fib[i] = 1;
         else 
            fib[i] = fib[i-1] + fib[i-2];
       }

    printf("The 10-th Fibonacci number is %i .\n", fib[i]);   
    /* Defect: Value of i is greater than allowed value of 9 */
}

配列 fib にはサイズ 10 が割り当てられています。fib の配列インデックスに許可される値は [0,1,2,...,9] です。変数 ifor ループから出るときの値は 10 です。したがって、printf ステートメントは i を用いて fib[10] にアクセスしようと試みます。

修正 — 配列のインデックスを配列の範囲内に維持

1 つの修正方法として、for ループの後で、fib[i] ではなく fib[i-1] を出力するとします。

#include <stdio.h>

void fibonacci(void)
{
   int i;
   int fib[10];

   for (i = 0; i < 10; i++) 
    {
        if (i < 2) 
            fib[i] = 1;
        else 
            fib[i] = fib[i-1] + fib[i-2];
    }

    /* Fix: Print fib[9] instead of fib[10] */
    printf("The 10-th Fibonacci number is %i .\n", fib[i-1]); 
}

printf ステートメントは、fib[10] ではなく fib[9] にアクセスします。

問題

範囲外にアクセスするポインターは、ポインターが範囲外でデリファレンスされる場合に発生ます。

ポインターにアドレスが割り当てられると、そのポインターにメモリのブロックが関連付けられます。そのポインターを使用してそのブロック外のメモリにアクセスすることはできません。

リスク

範囲外のポインターのデリファレンスは未定義の動作です。予測不能な値を読み取ったり、許可されていない位置へのアクセスを試みてセグメンテーション違反が発生したりする可能性があります。

修正方法

修正方法は欠陥の根本原因によって異なります。たとえば、ループ内のポインターをデリファレンスする際、次のいずれかの状況が発生したとします。

  • ループの上限が大きすぎる。

  • ポインターをインクリメントするためにポインター演算を使用する際、不適切な値でポインターを進めている。

この問題を修正するには、ループの範囲またはポインターのインクリメント値を変更する必要があります。

多くの場合、結果の詳細には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して逆のトレースを行い、これまでの関連するイベントを確認できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈も参照してください。

以下の修正例を参照してください。

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 - 範囲外にアクセスするポインター エラー
int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
   {
    ptr++;
    *ptr=i;
    /* Defect: ptr out of bounds for i=9 */
   }

 return(arr);
}

ptr には、サイズ 10*sizeof(int) のメモリ ブロックを指すアドレス arr が割り当てられます。for ループで、ptr は 10 回インクリメントされます。ループの最後の反復で、ptr は割り当てられたメモリ ブロックの外を指します。したがって、デリファレンスはできません。

修正 — ポインターが範囲内にあることをチェック

1 つの修正方法として、ptr のインクリメントとデリファレンスの順序を逆にすることができます。

int* Initialize(void)
{
 int arr[10];
 int *ptr=arr;

 for (int i=0; i<=9;i++)
     {
      /* Fix: Dereference pointer before increment */
      *ptr=i;
      ptr++;
     }

 return(arr);
}

最後のインクリメントの後で ptr は割り当てられたメモリ ブロックの外を指しますが、もうデリファレンスされることはありません。

チェック情報

決定可能性:決定不可能

バージョン履歴

R2019a で導入


1 Extracts from the standard "ISO/IEC TS 17961 Technical Specification - 2013-11-15" are reproduced with the agreement of AFNOR. Only the original and complete text of the standard, as published by AFNOR Editions - accessible via the website www.boutique.afnor.org - has normative value.