メインコンテンツ

到達不能コード チェックのレビューと修正

このトピックでは、Polyspace® Code Prover™[到達不能コード] チェックの結果を体系的にレビューする方法を説明します。

[到達不能コード] チェックの修正を判断するまでこれらの手順の 1 つ以上に従います。このチェックを修正する方法は複数あります。チェックおよびコードの例については、到達不能コードを参照してください。

チェックが防御的コードを表していると判断する場合、結果またはコードにコメントおよび正当化情報を追加し、コードを変更しなかった理由を説明しますPolyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処またはPolyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access)を参照してください。

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

  1. [結果のリスト] ペインまたは [ソース] ペインでチェックを選択します。

  2. [結果の詳細] ペインのメッセージと、[ソース] ペインの対応する到達不能コードを確認します。

    • [結果の詳細] ペインのこのメッセージは、コードのブロックが到達不能である理由を説明しています。

      Example unreachable code message

    • [ソース] ペインでは、到達不能コードがグレーで強調表示されます。

      到達不能コードの種類によっては、キーワードまたはコード ブロックがグレーで強調表示されることがあります。たとえば、if 条件式が常に true に評価される場合、if キーワードが強調表示されます。条件式が常に false に評価される場合、対応する到達不能なコード ブロックが強調表示されます。

  3. ブロックへ入ることを決める条件が満たされない場合、コード ブロックは通常到達不能です。条件を満たしていない理由を確認します。

    1. [ソース] で、値を決めるために条件に含まれる変数の上にカーソルを置きます。

    2. これらの値を使用し、条件を満たさない理由を確認します。

    メモ

    条件自体が冗長である場合があります。たとえば、常に true であるか、以下の組み合わせです。

    • || 演算子と常に true である別の条件。

    • && 演算子と常に false である別の条件。

    たとえば、次のコードでは最初の条件 x>0 が常に true であるため、条件 x%2==0 は冗長です。

    assert(x>0);
    if(x>0 || x%2 == 0)
    条件が冗長である場合、コードのブロックの代わりに条件自体がグレーでマークされます。

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

条件に含まれる各変数のデータ フローをトレースします。

次の例では、arg のデータ フローをトレースします。

void foo(void) {
    int x=0;
    .
    .
    bar(x);
    .
    .
}

void bar(int arg) {
    if(arg==0) {
        /*Block 1*/
    }
    else {
        /*Block 2*/
    }
}
barfoo からのみ呼び出される場合があります。bar の唯一の引数の値が 0 であるため、if(arg==0)else 分岐は到達不能です。

考えられる解決方法: bar を別の場所で呼び出さず、bar に渡される値が変化しないことがわかっている場合、bar 内の if-else ステートメントを削除し、Block 1 の内容のみを保持できます。

データ フローをトレースするには、チェックを選択し、[結果の詳細] ペインの情報を確認します。

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

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

  • それ以外の場合は、条件に含まれる変数ごとに、前のインスタンスを検索し、チェックの根本原因へ逆にトレースします。一般的な根本原因についての詳細は、手順 3: チェックの一般的な原因の検索を参照してください。

    変数に応じて、以下のナビゲーション ショートカットを使用し、前のインスタンスを検索します。以下の手順は、Polyspace ユーザー インターフェイスでのみ実行できます。

    変数変数の前のインスタンスの検索方法

    ローカル変数

    次のいずれかの方法を使用してください。

    • 変数の検索。

      1. 変数を右クリックします。[すべての参照を検索] を選択します。

        変数のすべてのインスタンスは、現在のインスタンスが強調表示されて [検索] ペインに表示されます。

      2. [検索] ペインで前のインスタンスを選択します。

    • ソース コードの参照。

      1. [ソース] ペインで変数をダブルクリックします。

        変数のすべてのインスタンスは強調表示されます。

      2. 上にスクロールして前のインスタンスを検索します。

    グローバル変数

    変数を右クリックします。オプション [変数アクセス ビューで表示] が表示される場合、変数はグローバル変数です。

    1. オプション [変数アクセス ビューで表示] を選択します。

      [変数アクセス] ペインでは、変数の現在のインスタンスが表示されます。

    2. このペインで、変数の前のインスタンスを選択します。

      変数の書き込み操作は write opterations arrow icon で示され、読み取り操作は read operations arrow icon で示されます。

    関数の戻り値

    ret=func();

    1. 関数定義を検索します。

      [ソース] ペインの func を右クリックします。オプションが存在する場合、[定義に移動] を選択します。Polyspace で定義を利用できない場合は、オプションを選択すると関数宣言に移動します。

    2. func の定義では、各 return ステートメントを特定します。関数が返す変数が逆にトレースするための新しい変数です。

    任意の操作に含まれる変数が前の操作に関連しているかどうかを判断することもできます。コード内の変数間の関係の検出を参照してください。

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

[到達不能コード] チェックの一般的な原因を確認します。

  • if テスト内で以下を確認します。

    • テスト対象である変数をテストしていること。

      たとえば、グローバル変数を隠すローカル変数が存在する可能性があります。グローバル変数のテストとして、ローカル変数をテストしている可能性があります。

    • if テスト内の演算の実行順序を設定するために小かっこを使用していること。

      たとえば、if((!a && b) || c) では if(!(a && b) || c) とは異なる演算順序が適用されます。かっこを使わない場合、操作は演算子の優先順位規則に従います。ルールにより演算が意図せぬ順序で実行される可能性があります。

    • 正しい場所で = および == 演算子を使用していること。

    考えられる解決方法: エラーがある場合、訂正します。

  • 以前に実行したテストを実行しているかどうかを確認します。

    冗長なテストは通常、関数の引数で発生します。同じテストが呼び出し元および呼び出される関数の両方で実行されています。

    void foo(void) {
        if(x>0)
            bar(x);
        .
        .
    }
    
    void bar(int arg) {
        if(arg==0) {
        }
    }

    考えられる解決方法: bar をまだ書かれていないコードなどで後で呼び出す場合、あるいは他のプログラムで bar を再利用する場合、bar でテストを保持します。それ以外の場合は、テストを削除します。

  • コードが break または return ステートメントの後にあるために到達不能なのかどうかを確認します。

    考えられる解決方法: 意図していない場所に break または return ステートメントを配置したかどうかを確認します。

  • 到達不能コードのセクションがコーディング規約に準拠するために存在するのかどうかを確認します。その場合、このセクションを保持します。

    たとえば、switch-case ステートメントの default ブロックは switch 変数の異常な値を取得するために用意されています。このような値が発生しない場合には、ブロックは到達不能です。ただし、ブロックを削除するとコーディング規約に違反する可能性があります。

  • 到達不能コードがコードの前方でオレンジ チェックに関連付けられているかどうかを確認します。オレンジ チェックの後、Polyspace は通常、エラーを含む実行パスを終了します。この終了が原因で、オレンジ チェックの後のコードはグレーで表示される場合があります。

    たとえば、ptrNULL を調べていなかった場合、Polyspace はオレンジ チェックをポインター ptr のデリファレンス上に付けます。ただし、デリファレンスの後、ptrNULL ではないと見なされます。テスト if(ptr==NULL)ptr のデリファレンスの後にある場合、Polyspace は対応するコード ブロックを到達不能としてマークします。

    他の例は、次を参照してください。

    考えられる解決方法: オレンジ チェックを調べます。上記の例では、テスト if(ptr==NULL) がデリファレンスの前ではなく、後で発生する理由を調べます。