EN JP CN

DBZ.GENERAL

DBZ.GENERAL

割り当てられたゼロの定数値がゼロ除算で使用されている可能性があります

ゼロを除数として除算やモジュロ演算に使用しようとすると、ランタイムエラーが発生します。ゼロによる除算の欠陥は、効果的でないエラー処理または競合状態のためにしばしば起こります。通常、プログラム終了の異常が発生します。値が C/C++ コードにおいて除算またはモジュロ演算の除数として使用される前に、ゼロに等しくないことを確認するためにチェックする必要があります。

DBZ チェッカーは、除算やモジュロ演算の除数としてゼロが使用されているインスタンスを検索します。

DBZ.GENERAL チェッカーは、ゼロ定数値をローカルで割り当てられた、または関数呼び出しの結果として、変数が明示的に使用されるか、除算やモジュロ演算の除数としてこれを使用する可能性がある関数に渡される状況にフラグを立てます。

脆弱性とリスク

通常、整数のゼロによる除算は、プロセスの失敗や例外を引き起こします。また、演算は成功するかもしれませんが、結果に誤りとなります。浮動小数のゼロでの除算は、より分かりにくくなります。これは、コンパイラの実装に依存しています。コンパイラが IEEE 浮動小数点標準規格 (IEEE 754) に従う場合、浮動小数をゼロで除算した結果は明確なものとなります。しかし、C および C++ 標準規格は IEEE 754 規格への準拠を強制しません。従って、浮動小数のゼロでの除算の結果は、C および C++ では明確ではなく、従って、プロセスが失敗したり例外が発生したりする可能性があります。

ゼロによる除算の指摘は通常、効果的でない例外処理が原因で発生します。この脆弱性を回避するために、これを除算やモジュロ演算の除数として使用する前に、ゼロ値がないかを確認してください。

脆弱コード例

1  int compute_mean(int array[], size_t size)
2  {
3      int sum = 0;
4      for (size_t i = 0; i < size; ++i) {
5          sum += array[i];
6      }
7      return sum / size;
8  }
9  
10  void use_mean()
11  {
12      int size = 0;
13      int mean = compute_mean(0, size);
14  }

Klocwork は13 行目で指摘レポートを生成し、変数 ‘size’ の値が ‘compute_mean’ 呼び出し時に0であり、7 行目の除算の除数としてこの関数で使用されていることを示します。ゼロで除算することにより、予期しない結果や意図しない結果となる可能性があります。

修正コード例

1 int compute_mean(int array[], size_t size)
2  {
3      if (size == 0) {
4          return 0; // or exceptional case.
5      }
6
7      int sum = 0;
8      for (size_t i = 0; i < size; ++i) {
9          sum += array[i];
10     }
11     return sum / size;
12  }
13 
14  void use_mean()
15  {
16      int size = 0;
17      int mean = compute_mean(0, size);
18  }    

前のスニペットからの問題が修正されました:これにより、入力変数 ‘size’ が3行目にゼロ定数値の例外ケースがないかをチェックし、この特定ケースで除算が行われないようにします。

外部参考資料

拡張機能

このチェッカーは、Klocwork knowledge base (ナレッジベース) を利用して拡張できます。詳細については、C/C++ 解析のチューニングを参照してください。

制限事項

このチェッカーは、整数型でのみ動作します。浮動小数点型では動作しません。つまり、浮動小数点型の関連する欠陥はこのチェッカーでは検出されません。たとえば、次のようになります。
1  void do_dbz()
2  {
3     double myzero = 0.0;
4     int doit = 23 / myzero;    // Divide by zero will not be detected here since it is a floating-point type.
5  }
このチェッカーは、現在の解析関数の範囲外にあるゼロに割り当てられたグローバル変数では動作しません。つまり、グローバル変数の関連する欠陥はこのチェッカーでは検出されない可能性があります。たとえば、次のようになります。
1  static int myzero = 0;
2 
3  int do_dbz()
4  {
5     return 23 / myzero;
6  }
このチェッカーはゼロと評価する抽象的(象徴的)表現では動作しません。つまり、この種の理由の関連する欠陥はこのチェッカーでは検出されない可能性があります。たとえば、次のようになります。
1  void do_dbz_func(int x, int y)
2  {
3     int z = 23;
4     z /= x - y;    // Here, x == y will give 0 for x - y. Divide by zero will not detected.
5  }
6
7  void do_dbz(int x)
8  {   
9     do_dbz_func(x, x);   // Divide by zero will happen here since x - x = 0. Not detected by this checker.
10 }