メインコンテンツ

不適切にデリファレンスされたポインター チェックのレビューと修正

このトピックでは、Polyspace® Code Prover™[不適切にデリファレンスされたポインター] チェックの結果を体系的にレビューする方法を説明します。

[不適切にデリファレンスされたポインター] チェックの修正を判断するまでこれらの手順の 1 つ以上に従います。このチェックを修正する方法は複数あります。チェックおよびコードの例については、不適切にデリファレンスされたポインターを参照してください。

特にオレンジ チェックに対して、チェックが実際のエラーを表すのではなく、コードに該当しない Polyspace 前提条件を表していると判定できます。前提条件を緩和するのに解析オプションを使用できる場合、そのオプションを使用して検証を再実行します。それ以外の場合は、結果またはコードにコメントおよび正当化情報を追加できます。

すべてのチェックに適用される一般的なワークフローについては、Polyspace デスクトップ ユーザー インターフェイスでの Code Prover の結果の解釈またはPolyspace Access Web インターフェイスでの Code Prover の結果の解釈 (Polyspace Access)を参照してください。

手順 1: チェック情報の解釈

カーソルをデリファレンス演算子の上に置きます。

ツールヒントから次の情報を取得します。

  • ポインターが NULL の可能性があるかどうか。

    次の例では、ptr はデリファレンス時に NULL である可能性があります。

    考えられる解決方法: NULL でない場合のみ、ptr をデリファレンスします。

    if(ptr !=NULL)
        *ptr = 1;
    else 
        /* Alternate action */

  • ポインターが、割り当てられたバッファーの外側を指すかどうか。ポインターは、ポインター サイズとオフセットの合計がバッファー サイズよりも大きい場合に、割り当てられたバッファーの外側を指します。

    次の例では、オフセット サイズ (4096 バイト) とポインター サイズ (4 バイト) を合わせるとバッファー サイズ (4096 バイト) よりも大きいことを示しています。ポインターが配列を指す場合、

    • バッファー サイズは配列サイズです。

    • オフセットは配列の先頭とポインターの現在の位置の差です。

    考えられる解決方法: ポインターが、割り当てられたバッファーの外側を指す理由を調べます。

  • バッファー サイズが不明であるために、ポインターが割り当てられたバッファーの外側を指す可能性があるかどうか。

    次の例では、バッファー サイズは不明です。

    考えられる解決方法: ポインターに以下が割り当てられているかどうかを調べます。

    • 未定義の関数の戻り値。

    • 動的なメモリ割り当て関数の戻り値。Polyspace では、動的メモリ割り当てからバッファー サイズを判別できない場合があります。

    • void* などの異なるタイプの別のポインター。

  • 不適切なポインターのデリファレンスについて考えられる根本原因 (ツールヒントに示されている場合)。

    次の例では、スタブ関数 getAddress が考えられる原因として識別されています。

    考えられる解決方法: 不適切にデリファレンスされたポインターを回避するには、getAddress の戻り値を制約して、コードの外部にあるデザイン情報を提供します。たとえば、getAddress が要素が 10 の配列にポインターを返すよう指定します。詳細については、スタブ関数に関する Code Prover の仮定を参照してください。

手順 2: チェックの根本原因の判定

チェックを選択し、[結果の詳細] ペインの情報を確認します。

  • [結果の詳細] ペインでチェックにつながる命令の順序が表示される場合、各命令を選択し、根本原因へとトレースします。

  • [結果の詳細] ペインでチェックに対して考えられる原因の行番号が表示される場合、Polyspace ユーザー インターフェイスの [ソース] ペインで右クリックします。[行に移動] を選択します。

  • それ以外の場合は、エラーの性質に基づいて、根本原因を検出するために次のいずれかの方法を使用します。以下の手順は、Polyspace ユーザー インターフェイスでのみ実行できます。

    エラー根本原因の検出方法
    ポインターは NULL の可能性があります。

    ポインターに NULL 値が割り当てられている、あるいは明確なアドレスが割り当てられていない実行パスを検索します。

    1. ポインターを右クリックし、[すべての参照を検索] を選択します。

    2. ポインターにアドレスが割り当てられているそれぞれの前のインスタンスを検索します。

    3. インスタンスごとに、[ソース] ペインでカーソルをポインターの上に置きます。ツールヒントは、ポインターが NULL である可能性があるかどうかを示します。

      考えられる解決方法: ポインターが NULL の可能性がある場合、割り当ての直後に NULL へのチェックを付けます。

      if(ptr==NULL)
        /* Error handling*/
      else {
        .
        .
      	}
    4. ポインターが NULL ではない場合、割り当てが条件付きステートメントの分岐でのみ発生するのかどうかを確認します。分岐が実行されないときは調べます。

      考えられる解決方法: 条件付きステートメントのすべての分岐で有効なアドレスをポインターに割り当てます。

    ポインターはバッファーにより許容される範囲外を指す場合があります。

    1. 割り当てられたバッファーのサイズを調べます。

      1. [検索] タブで、ポインターが指す変数名を入力します。この変数名はチェックに関するツールヒントに既に表示されています。

      2. 変数定義を検索します。通常、これは最初の検索結果です。

        変数が配列である場合、配列サイズに注意してください。変数が構造体である場合、[検索] タブで構造体の型名を検索し、構造体の定義を見つけます。ポインターが指す構造体フィールドのサイズに注意してください。

    2. ポインターが割り当てられたバッファーの外側を指す理由を調べます。

      1. ポインターを右クリックし、[すべての参照を検索] を選択します。

      2. ポインターのすべてのインクリメントまたはデクリメントを特定します。インクリメントまたはデクリメントが意図されていたかどうかを確認します。

        考えられる解決方法: 意図していないポインター演算を削除します。割り当てられたバッファーの外側にポインターを取るポインター演算を回避するには、参照ポインターを使用してその初期値を保存します。ポインターの各算術演算後、参照ポインターと比較してその差が割り当てられたバッファー外であるかを確認します。

手順 3: チェックの一般的な原因の検索

[不適切にデリファレンスされたポインター] チェックの一般的な原因を確認します。

  • 配列を移動するのにポインターを使用する場合、代わりに配列インデックスを使用できるかどうかを確認します。

    配列内を移動するポインター演算を使用すると、MISRA C™:2023 Rule 18.4 の違反が報告されます。このルールの違反の有無をチェックするには、Polyspace Bug Finder™ を使用します。MISRA C:2023 Rule 18.4 を参照してください。

  • 構造体のフィールドを移動するのにポインターを使用するかどうかを確認します。

    Polyspace では、構造体のあるフィールドへのポインターが別のフィールドを指すことは許可されていません。この動作を許可するには、オプションフィールド間のポインター演算を有効にする (-allow-ptr-arith-on-struct)を使用します。

  • 構造体を指すがそのすべてのフィールドに対して十分なメモリをもたないポインターをデリファレンスしているかどうかを確認します。通常、このようなポインターはより小さい構造体への型キャストによって生じます。

    Polyspace ではこのようなデリファレンスは許可されていません。この動作を許可するには、オプション構造体の不完全または部分的割り当てを許可する (-size-in-bytes)を使用します。

  • オレンジ チェックが関数本体で発生する場合、異なる呼び出しで異なるサイズの配列を関数に渡しているかどうかを確認します。

    特定の呼び出しによってオレンジ チェックが発生しているのかどうかを確認します。チュートリアルについては、ランタイム エラーのある関数呼び出しの特定を参照してください。

  • 互換性のないサイズの 2 つのポインター間でキャストが行われているかどうかを確認します。

手順 4: Polyspace の前提条件へのチェックをトレース

コードの前方で発生する Polyspace 前提条件にオレンジ チェックをトレースできるかどうかを確認します。前提条件があてはまらない場合、結果またはコードにコメントまたは正当化情報を追加します。Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処またはPolyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access)を参照してください。

たとえば、ポインターが未定義の関数からアドレスを受け取るとします。ここで、次のようにします。

  1. Polyspace は、関数が NULL を返す可能性があると仮定します。

    したがって、ポインターのデリファレンスはオレンジになります。

  2. また、Polyspace ではポインターの型に基づいてバッファー サイズも仮定します。

    ポインターをインクリメントすると、割り当てられたバッファーを超えます。インクリメントの後に続くポインターのデリファレンスはオレンジです。

  3. 関数が非 NULL 値を返すことがわかっている場合、あるいは真に割り当てられたバッファーがわかっている場合、コードにコメントおよび正当化情報を追加し、コードを変更しなかった理由を説明します。

詳細については、Code Prover 解析の前提条件を参照してください。

メモ

オレンジ チェックを正当化する前に、コード設計を改善できるかどうかを十分に検討してください。