メインコンテンツ

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

CWE Rule 369

Divide By Zero

R2023a 以降

説明

ルールの説明

The product divides a value by zero.

Polyspace 実装

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

  • 浮動小数点数のゼロ除算

  • 整数のゼロ除算

  • 汚染された除算演算子

  • 汚染されたモジュロ演算子

すべて展開する

問題

この問題は、除算演算の分母がゼロ値の浮動小数点数になる可能性がある場合に発生します。

リスク

ゼロ除算はプログラムをクラッシュさせる可能性があります。

修正方法

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

除算の前に分母がゼロ値かどうかをチェックしてエラーを処理することをお勧めします。次のように除算を直接実行するのは避けます。

res = num/den;
除算を実行する前に分母のゼロ値を処理するライブラリ関数を使用します。
res = div(num, den);

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

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

既定では、Bug Finder 解析は無限大と NaNs を認識しません。結果が無限大および NaNs になる演算には、欠陥としてフラグが設定される可能性があります。コードで無限大および NaN の値を処理するには、オプション [非有限の浮動小数点を検討] (-allow-non-finite-floats) を使用します。

チェッカーの拡張

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

例 — 浮動小数点数のゼロでの除算
float fraction(float num)
{
    float denom = 0.0;
    float result = 0.0;

    result = num/denom; //Noncompliant

    return result;
}

denom がゼロであるため、num/denom でゼロ除算エラーが発生します。

修正 — 除算の前にチェック
float fraction(float num)
{
    float denom = 0.0;
    float result = 0.0;

    if( ((int)denom) != 0)
        result = num/denom;

    return result;
}

除算の前に、分母がゼロかどうかを確認するためのテストを追加して、除算が実行される前にチェックします。denom が常にゼロである場合は、この修正により Polyspace® の結果にデッド コードの欠陥が報告される可能性があります。

修正 — 分母を変更

1 つの修正方法として、denom がゼロでなくなるように分母の値を変更することができます。

float fraction(float num)
{
    float denom = 2.0;
    float result = 0.0;

    result = num/denom;

    return result;
}
問題

この問題は、除算演算またはモジュロ演算の分母がゼロ値の整数になる可能性がある場合に発生します。

リスク

ゼロ除算はプログラムをクラッシュさせる可能性があります。

修正方法

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

除算の前に分母がゼロ値かどうかをチェックしてエラーを処理することをお勧めします。次のように除算を直接実行するのは避けます。

res = num/den;
除算を実行する前に分母のゼロ値を処理するライブラリ関数を使用します。
res = div(num, den);

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

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

チェッカーの拡張

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

例 — 整数のゼロによる除算
int fraction(int num)
{
    int denom = 0;
    int result = 0;

    result = num/denom; //Noncompliant

    return result;
}

denom がゼロであるため、num/denom でゼロ除算エラーが発生します。

修正 — 除算の前にチェック
int fraction(int num)
{
    int denom = 0;
    int result = 0;

    if (denom != 0)
        result = num/denom;

    return result;
}

除算の前に、分母がゼロかどうかを確認するためのテストを追加して、除算が実行される前にチェックします。denom が常にゼロである場合は、この修正により Polyspace の結果にデッド コードの欠陥が報告される可能性があります。

修正 — 分母を変更

1 つの修正方法として、denom がゼロでなくなるように分母の値を変更することができます。

int fraction(int num)
{
    int denom = 2;
    int result = 0;

    result = num/denom;

    return result;
}
例 — ゼロによるモジュロ演算
int mod_arr(int input)
{
    int arr[5];
    for(int i = 0; i < 5; i++)
    {
        arr[i] = input % i; //Noncompliant
    }

    return arr[0]+arr[1]+arr[2]+arr[3]+arr[4];
}

この例では、Polyspace がモジュロ演算にゼロ除算のフラグを立てます。モジュロは本質として除算演算であるため、除数 (右辺引数) をゼロにすることはできません。このモジュロ演算では、除数として for ループのインデックスを使用しています。しかし、for ループはゼロから開始されるので、反復子にはできません。

修正 — 演算の前に除数をチェック

1 つの修正方法として、モジュロ演算の前に除数をチェックします。この例では、モジュロ演算の前に指数 i がゼロかどうかを確認します。

int mod_arr(int input)
{
    int arr[5];
    for(int i = 0; i < 5; i++)
    {
        if(i != 0)
        {
             arr[i] = input % i;
        }
        else
        {
             arr[i] = input;
        }
    }

    return arr[0]+arr[1]+arr[2]+arr[3]+arr[4];
}
修正 — 除数を変更

別の修正方法として、除数を非ゼロの整数に変更します。この例では、% 演算の前に指数に 1 を加算して、ゼロ除算を回避しています。

int mod_arr(int input)
{
    int arr[5];
    for(int i = 0; i < 5; i++)
    {
         arr[i] = input % (i+1);
    }

    return arr[0]+arr[1]+arr[2]+arr[3]+arr[4];
}
問題

この問題は、除算演算内の整数オペランドの一方または両方がセキュリティで保護されていないソースから取得された場合に発生します。

リスク

  • 分子 (被除数) が可能な限りの最小値であり、分母 (除数) が -1 である場合、除算演算は結果が現在の変数のサイズでは表現できないためオーバーフローします。

  • 分母がゼロである場合、除算演算は失敗し、プログラムがクラッシュがする可能性があります。

こうしたリスクは、恣意的なコードの実行に利用される可能性があります。このようなコードは通例において、プログラムの暗黙的なセキュリティ ポリシーの範囲外です。

修正方法

除算を実行する前に、オペランドの値を検証します。0 または -1 の分母や、最小の整数値の分子についてチェックします。

チェッカーの拡張

既定では、Polyspace は外部ソースからのデータは汚染されていると仮定します。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary] を使用します。

例 — 関数の引数の除算
#include <limits.h>
#include <stdio.h>

extern void print_int(int);

int taintedintdivision(void) {
    long num, denum;
    scanf("%lf %lf", &num, &denum);
    int r =  num/denum; //Noncompliant //Noncompliant
    print_int(r);
    return r;
}

この関数例では、2 つの引数変数の除算を行い、それを表示して結果を返します。その引数値は不明であり、ゼロ除算や整数オーバーフローの原因となることがあります。

修正 — 値をチェック

1 つの修正方法として、除算を実行する前に分子と分母の値をチェックします。

#include <limits.h>
#include <stdio.h>

extern void print_long(long);

int taintedintdivision(void) {
    long num, denum;
    scanf("%lf %lf", &num, &denum);
    long res= 0;
    if (denum!=0 && !(num==INT_MIN && denum==-1)) {
        res = num/denum;
    }
    print_long(res);
    return res;
}
問題

この問題は、残余演算 (%) 内の整数オペランドの一方または両方がセキュリティで保護されていないソースから取得された場合に発生します。

リスク

  • 2 番目の残余オペランドが 0 である場合、残余演算は失敗し、プログラムはクラッシュします。

  • 2 番目の残余オペランドが -1 である場合、オーバーフローし得る除算演算を基に残余演算が実装されていると、その残余演算はオーバーフローする可能性があります。

  • オペランドの 1 つが負である場合、演算の結果は不確定になります。C89 ではモジュロ演算は標準化されていないため、負のオペランドによる結果は処理系定義となります。

こうしたリスクは、攻撃者によってプログラムあるいはターゲット一般へのアクセスに利用される場合があります。

修正方法

モジュロ演算を実行する前に、オペランドの値を検証します。2 番目のオペランドの値が 0-1 かどうかをチェックします。両方のオペランドの値が負の値かどうかをチェックします。

チェッカーの拡張

既定では、Polyspace は外部ソースからのデータは汚染されていると仮定します。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary] を使用します。

例 — ユーザー入力によるモジュロ
#include <stdio.h>
extern void print_int(int);

int taintedintmod(void) {
    int userden;
    scanf("%d", &userden);
    int rem =  128%userden; //Noncompliant //Noncompliant
    print_int(rem);
    return rem;
}

この例では、関数がユーザー入力を使用してモジュロ演算を実行します。残余を計算する前に、プログラムをクラッシュさせる可能性のある 0 や -1 などの値に対して入力がチェックされていません。

修正 — オペランドの値をチェック

1 つの修正方法として、モジュロ演算を実行する前にオペランドの値をチェックします。次に示す修正例では、モジュロ演算は 2 番目のオペランドが 0 より大きい場合にのみ続行します。

#include<stdio.h>
extern void print_int(int);

int taintedintmod(void) {
    int userden;
    scanf("%d", &userden);
    int rem = 0;
    if (userden > 0 ) { 
        rem = 128 % userden; 
    }
    print_int(rem);
    return rem;
}

チェック情報

カテゴリ: Numeric Errors

バージョン履歴

R2023a で導入