DBZ.GENERAL

赋值的零常量值可能在除以零的情况中使用

尝试在除法或模运算中使用零作为除数会导致运行时错误。错误处理或争用条件无效时,经常出现除以零的情况,并且通常会导致程序异常终止。在 C/C++ 代码中将值用作除法或模运算的除数之前,必须进行检查以确认值不为零。

DBZ 检查器会查找零常量值用作除法或模运算除数的实例。

DBZ.GENERAL 检查器会标记以下情况:变量在局部赋值为零常数值,或由于函数调用赋值为零常数值,而后续又需要在不进行零值检查的情况下,可能被显式使用或传递到可能将其用作除法或模运算除数的函数。

漏洞与风险

整数除以零通常会导致进程失败或异常。运算也可能成功,但会给出错误答案。浮点数除以零则更为微妙,具体取决于编译器的实施情况。如果编译器遵循 IEEE 浮点标准 (IEEE 754),则浮点数除以零会得到明确的结果。然而,C 和 C++ 标准不会强制遵循 IEEE 754。因此,浮点数除以零在 C 和 C++ 中具有未定义的行为,可能导致进程失败或异常。

异常处理无效时,经常出现除以零的情况。为避免此漏洞,在将值用作除法或模运算的除数之前,检查该值是否为零。

漏洞代码示例

复制
  int compute_mean(int array[], size_t size)
  {
      int sum = 0;
      for (size_t i = 0; i < size; ++i) {
          sum += array[i];
      }
      return sum / size;
  }
  
  void use_mean()
  {
      int size = 0;
      int mean = compute_mean(0, size);
  }

Klocwork 针对第 13 行生成问题报告,这表示在调用 compute_mean 时变量 size 的值为 0,并且该值用作第 7 行中除法运算的除数。除以零会产生无法预料的意外结果。

修正代码示例

复制
 int compute_mean(int array[], size_t size)
  {
      if (size == 0) {
          return 0; // or exceptional case.
      }

      int sum = 0;
      for (size_t i = 0; i < size; ++i) {
          sum += array[i];
     }
     return sum / size;
  }
 
  void use_mean()
  {
      int size = 0;
      int mean = compute_mean(0, size);
  }

前一代码段中的问题已修复:在第 3 行检查输入变量 size 是否有零常量值的异常情况,同时防止在该特定情况中出现除法运算。

安全培训

应用程序安全培训材料由 Secure Code Warrior 提供。

扩展

此检查器可通过 Klocwork 知识库进行扩展。有关详情,请参阅调整 C/C++ 分析。

限制

此检查器不处理当前所分析函数之外赋值为零的全局变量。这意味着此检查器检测不到涉及全局变量的缺陷。例如:
复制
  static int myzero = 0;
 
  int do_dbz()
  {
     return 23 / myzero;
  }
此检查器不处理计算为零的抽象符号表达式。这意味着此检查器检测不到涉及此类原因的缺陷。例如:
复制
  void do_dbz_func(int x, int y)
  {
     int z = 23;
     z /= x - y;    // Here, x == y will give 0 for x - y.Divide by zero will not detected.
  }

  void do_dbz(int x)
  {   
     do_dbz_func(x, x);   // Divide by zero will happen here since x - x = 0.Not detected by this checker.
 }