メインコンテンツ

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

CERT C: Rec.MSC12-C

Detect and remove code that has no effect or is never executed

説明

ルール定義

影響がないか実行されないコードを検出して削除します。1

Polyspace 実装

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

  • 到達不能コード

  • デッド コード

  • 無意味な if

  • 読み取りのない書き込み

すべて展開する

問題

この問題は、到達不能なコードがプロジェクトに含まれている場合に発生します。

リスク

プログラムが未定義の動作を示さない限り、到達不能コードは実行されません。到達不能コードはプログラムの出力に影響を与えられません。到達不能コードの存在はプログラム ロジックにエラーがあることを示している可能性があります。コンパイラにより削除されない到達不能コードはリソースを無駄に使用します。次に例を示します。

  • ターゲット マシンのメモリ領域を占有する。

  • 到達不能コードの存在により、到達不能コード周辺で制御を移行するときに、コンパイラはより長く時間のかかるジャンプ命令を選択する場合がある。

  • ループ内で、ループ全体が命令キャッシュに配置されない可能性がある。

例 - return ステートメントに続くコード
enum light { red, amber, red_amber, green };
void report_color(enum light);
enum light next_light ( enum light color )
{
    enum light res;

    switch ( color )
    {
    case red:
        res = red_amber;
        break;
    case red_amber:
        res = green;
        break;
    case green:
        res = amber;
        break;
    case amber:
        res = red;
        break;
    default:
    {
        error_handler ();
        break;
    }
    }

    report_color(res);
    return res;
    res = color;     /* Non-compliant */
}

この例では、return ステートメントの後に到達不能な演算があるため、ルールに違反しています。

問題

この問題は、削除してもプログラムの動作に影響しない到達可能な操作が解析で検出された場合に発生します。

Polyspace® Bug Finder™ は、解析中に無駄な書き込み操作を検出します。

リスク

到達可能ではあるものの、削除してもプログラムの動作に影響しない演算は、デッド コードとなります。

デッド コードの存在はプログラム ロジックのエラーを示している可能性があります。コンパイラはデッド コードを削除できるため、デッド コードの存在によりコード レビュー担当者が混乱する可能性があります。

__asm ( "NOP" ); などの言語拡張を含む演算は、デッド コードとは見なされません。

例 - 冗長な演算
extern volatile unsigned int v;
extern char *p;

void f ( void ) {
    unsigned int x;


    ( void ) v;      /* Compliant - Exception*/
    ( int ) v;       /* Non-compliant  */
    v >> 3;          /* Non-compliant  */

    x = 3;           /* Non-compliant - Detected in Bug Finder only */

    *p++;            /* Non-compliant  */
    ( *p )++;        /* Compliant  */
}

この例では、ある変数に対し演算が実行され、その演算の結果が使用されていない場合、ルールに違反します。次に例を示します。

  • 変数 v に対する演算 (int)>> は、その結果が使用されていないため冗長です。

  • 演算 = は、ローカル変数 x が演算の後で読み取られないため冗長です。

  • p++ に対する演算 * は、その結果が使用されていないため冗長です。

次の場合、このルールに違反しません。

  • 変数が void にキャストされる。キャストにより、値の不使用が意図的であることが示されます。

  • 演算の結果が使用されている。たとえば、p に対する演算 * は、*p がインクリメントされるため冗長ではありません。

問題

この問題は、条件が常に真である if ステートメントで発生します。この欠陥は if ステートメントが else ステートメントを伴わない時のみ発生します。

この欠陥は if ステートメントを削除してもコード実行に違いがないときに、不要な if ステートメントを表示します。

リスク

不要な if ステートメントは多くの場合、コーディング エラーを示します。おそらく、if 条件が適切にコーディングされていないか if ステートメントが完全に不要です。

修正方法

修正方法は欠陥の根本原因によって異なります。たとえば、同じ実行パスで 2 回チェックされるエラー状態が根本原因で、2 回目のチェックが冗長になっている可能性があります。

修正方法は欠陥の根本原因によって異なります。多くの場合、結果の詳細 (または Polyspace as You Code のソース コード ツールヒント) には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して、欠陥に関連する変数のこれまでの参照を検索し、関連するイベントを検出できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈またはPolyspace Access Web インターフェイスでの Bug Finder の結果の解釈 (Polyspace Access)も参照してください。

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

冗長な条件が防御的なコーディング手法を表すもので、問題を修正する必要がない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 – 列挙型を含む if
typedef enum _suit {UNKNOWN_SUIT, SPADES, HEARTS, DIAMONDS, CLUBS} suit;
suit nextcard(void);
void do_something(suit s);

void bridge(void)
{
    suit card = nextcard();
    if ((card < SPADES) || (card > CLUBS)){
        card = UNKNOWN_SUIT;
    }

    if (card < 7) { //Noncompliant
        do_something(card);
    }
}

suit 型は 5 つのオプションで列挙されます。ただし、条件式 card < 7card の最大値が 5 であるため常に真と評価されます。if ステートメントは不要です。

修正 1 — 条件を変更する

1 つの修正方法としてコードの if 条件を変更することができます。この修正では、7 は UNKNOWN_SUIT に変更され、card 型に直接関連付けます。

typedef enum _suit {UNKNOWN_SUIT, SPADES, HEARTS, DIAMONDS, CLUBS} suit;
suit nextcard(void);
void do_something(suit s);

void bridge(void)
{
    suit card = nextcard();
    if ((card < SPADES) || (card > CLUBS)){
        card = UNKNOWN_SUIT;
    }

    if (card > UNKNOWN_SUIT) {
        do_something(card);
    }
}
修正 — if の削除

別の修正方法として、コード内の if 条件を削除します。条件は常に真であるため、条件を削除しコードを単純化できます。

typedef enum _suit {UNKNOWN_SUIT, SPADES, HEARTS, DIAMONDS, CLUBS} suit;
suit nextcard(void);
void do_something(suit s);

void bridge(void)
{
    suit card = nextcard();
    if ((card < SPADES) || (card > CLUBS)){
        card = UNKNOWN_SUIT;
    }

    do_something(card);
}
問題

この問題は、変数に代入された値が読み取られない場合に発生します。

たとえば、変数に値を書き込んだ後、前の値を読み取る前に 2 番目の値を書き込みます。この最初の書き込み操作は冗長です。

リスク

冗長な書き込み操作は多くの場合、プログラミング エラーを示します。たとえば、2 つの連続した書き込み操作の間に変数を読み取るのを忘れていたり、意図せずに別の変数を読み取っていたりします。

修正方法

変数に書き込んだが、後にその変数を読み取っていない理由を特定します。名前が似ている別の変数を誤って読み取っているなど、一般的なプログラミング エラーを探します。

書き込み操作が冗長であると判断したら、その操作を削除します。

例 – 読み取りを進めずに書き込むエラー
void sensor_amplification(void)
{
    extern int getsensor(void);
    int level;

    level = 4 * getsensor();             //Noncompliant
    /* Defect: Useless write */
}

変数 level に値 4 * getsensor() が代入された後、この値は読み取られていません。

修正 — 代入後に値を使用

1 つの修正方法として、代入後に変数 level を使用することができます。

#include <stdio.h>

void sensor_amplification(void)
{
    extern int getsensor(void);
    int level;

    level = 4 * getsensor(); 
    
    /* Fix: Use level after assignment */
    printf("The value is %d", level);
    
}

変数 level は新しい値を読み取ったうえで出力されます。

チェック情報

グループ: Rec.48.その他 (MSC)

バージョン履歴

R2019a で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.