メインコンテンツ

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

CERT C++: INT33-C

Ensure that division and remainder operations do not result in divide-by-zero errors

説明

ルール定義

除算や残余の演算でゼロ除算エラーが発生しないようにします。1

Polyspace 実装

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

  • 整数のゼロ除算

  • 汚染された除算演算子

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

チェッカーの拡張

次の場合は、より厳密な解析を実行するように、このチェッカーを拡張します。

  • 入力値が不明であり、入力のサブセットのみがエラーの原因となっている場合、既定の Bug Finder 解析では "整数のゼロ除算" を検出しない場合があります。特定のシステム入力値が原因でこの問題が発生するかどうかをチェックするには、より厳密な Bug Finder 解析を実行してください。特定のシステム入力値から欠陥を見つけるための Bug Finder チェッカーの拡張を参照してください。

  • 既定の Bug Finder 解析では、現在の解析境界の外部からの特定の入力に関する "汚染された除算演算子""汚染されたモジュロ演算子" 問題にフラグを設定しない場合があります。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary] を使用します。

すべて展開する

問題

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

リスク

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

修正方法

修正方法は欠陥の根本原因によって異なります。多くの場合、結果の詳細には欠陥につながる一連のイベントが表示されます。このイベント リストを使用して、分母変数がどのようにゼロ値を取得したのかを確認します。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して逆のトレースを行い、これまでの関連するイベントを確認できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈も参照してください。

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

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

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

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

例 - 整数のゼロによる除算
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 の分母や、最小の整数値の分子についてチェックします。

例 - 関数の引数の除算
#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
    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;
}
問題

汚染されたモジュロ演算子では、残余演算 % のオペランドがチェックされます。Bug Finder では、汚染されたオペランドが 1 つ以上含まれているモジュロ演算にフラグを立てます。

リスク

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

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

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

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

修正方法

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

例 - 関数の引数によるモジュロ
#include <stdio.h>
extern void print_int(int);

int taintedintmod(void) {
    int userden;
    scanf("%d", &userden);
    int rem =  128%userden; //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;
}

チェック情報

グループ: 03.整数 (INT)

バージョン履歴

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.