【C言語】
ゼロ除算の見つけ方
(Divide By Zero)

warning: division by zero

警告:ゼロ除算
[-Wdiv-by-zero]

■1.ゼロ除算を見つけるのは難しい

コンパイラの警告や静的解析ツールを使用しても
ゼロ除算を見つけるのは難しい。

人海戦術で単純検索してもうまくいかない。

そんな時は逆アセンブルしてゼロ除算を検索すると
うまくいくかもしれない。

■2.ゼロ除算問題の簡単な例

#include    <stdio.h>
int main(void)
{
    int x = 0 ; 
    int y = 3 ;
    printf("%d\n",y/x) ;    //検出できない
    printf("%f\n",y/0.0) ;  //意図的かもしれない
    printf("%d\n",y/0) ;    //検出できる
}

ツールでは ゼロ除算 問題を検出できない場合がほとんどです。
gccでは
8行目のように分母が定数0の時しか検出できません。
6行目のように分母が変数の時は検出できません。


■3.ゼロ除算問題の見つけ方

ゼロ除算問題が発生してしまった時、
同様の問題がないか確認するために
割り算を行っている箇所をソースコードから
見つけ出す必要があります。


しかし ”/” や”%”を以下のように単純検索してもうまくいきません。

 $grep  ”/”  *.c

⇒コメントの”//” や ”/*” ばかり膨大な量が検索されます。


こんな時はCソースから割り算を検索するのではなくて
一度逆アセンブルして”div” 命令などを検索したほうが
早いかもしれません。

■4.”div”命令を検索するSHELL

gcc -c -g div.c -O2
objdump div.o --disassemble --line-numbers --source > TMP
grep div TMP

■5.ガード処理を抜けるゼロ除算の失敗例

int f(int x,double d)
{
    if(d) {//ゼロ除算ガード
        printf("THEN %f\n",x/d);
        return  x/(int)d;
    } else {
        printf("ELSE\n");
        return  0;
    }
}
int main(void)
{
    f(2,0.14142);
}

除算命令を見つけたらガード処理があるか
「人力」で確認する必要があります。
その際上記コードのように見かけ上
ゼロ除算のガード処理があっても
すり抜ける場合があるので注意して下さい。
3行目の判定では浮動小数点変数 d はゼロではないので then 節へ行きますが、
5行目の(int)dで丸めたためゼロになってしまいます。

■6.ゼロ除算後の不適切なガード処理

(warning): Either the condition ‘y==0’ is redundant or there is division by zero at line 3.

警告:ゼロ除算後のガード処理は無駄

[(warning)zerodivcond]

#include    <stdio.h>
int 割り算(int 分子,int 分母) 
{
    int 結果 = 分子/分母;
    if(分母 == 0){//ガード処理
        return  0;
    }
    return  結果;
}
int main(void) {
    printf("%d\n",割り算(3,0)) ;
}

分子/分母を実行する前に
if(分母 == 0)でガードしてください。

参考:

CWE-369: Divide By Zero

INT33-C. 除算および剰余演算がゼロ除算エラーを引き起こさないことを保証する

https://www.jpcert.or.jp/sc-rules/c-int33-c.html