warning: division by zero
警告:ゼロ除算
[-Wdiv-by-zero]
■この記事の概要
この記事では、C言語でのゼロ除算の問題を取り上げ、gcc
やツールでの検出限界について説明しています。ゼロ除算が起きる状況を具体例とともに解説し、逆アセンブルを活用した検出法や安全なコーディングの重要性を強調しています。
■0で割り算すると大抵の環境では浮動小数点例外が発生
浮動小数点例外(Floating point exception)が
発生するとプログラムは強制終了します。
そしてお客様に呼び出され(以下略)
■ゼロ除算問題の例
#include <stdio.h>
void f1(void){
int x = 1;
printf("%d\n",x/0) ; //検出できる
}
void f2(void){
int x = 1;
int y = 0;
printf("%d\n",x/y) ; //検出できない
}
int f3(int x,int y){
return x/y; //検出できない
}
int main(void){
int x = 1;
int y = 0;
printf("%d\n",f3(x,y));
}
ツールでは ゼロ除算 問題を検出できない場合がほとんどです。
筆者環境下のgcc -Wall -Wextraでは
分母が定数0の時しか検出できません。
分母が変数の時は検出できませんでした。
■ゼロ除算を見つけるのは難しい
コンパイラの警告や静的解析ツールを使用してもゼロ除算を見つけるのは難しいです。
人海戦術で単純検索してもうまくいきません。
●除算命令(div)の見つけ方
ゼロ除算問題が発生してしまった時、
同様の問題がないか確認するために
割り算を行っている箇所をソースコードから
見つけ出す必要があります。
しかし ”/” や”%”を以下のように単純検索してもうまくいきません。
$grep ”/” *.c
⇒コメントの”//” や ”/*” ばかり膨大な量が検索されます。
こんな時はCソースから割り算を検索するのではなくて
一度逆アセンブルして”div” 命令などを検索したほうが
早いかもしれません。
●”div”命令を検索するSHELL
gcc -c -g ./div.c
objdump div.o \
--disassemble \
--line-numbers \
--source | grep div
➡実行結果
+ gcc -c -g ./div.c
./div.c: In function ‘f1’:
./div.c:4:20: warning: division by zero [-Wdiv-by-zero]
4 | printf("%d\n",x/0) ; //検出できる
| ^
+ objdump div.o --disassemble --line-numbers --source
+ grep div
div.o: file format elf64-x86-64
/mnt/f/DivideByZero/./div.c:2
/mnt/f/DivideByZero/./div.c:3
/mnt/f/DivideByZero/./div.c:4
1c: f7 f9 idiv %ecx
/mnt/f/DivideByZero/./div.c:5
/mnt/f/DivideByZero/./div.c:6
/mnt/f/DivideByZero/./div.c:7
/mnt/f/DivideByZero/./div.c:8
/mnt/f/DivideByZero/./div.c:9
55: f7 7d fc idivl -0x4(%rbp)
/mnt/f/DivideByZero/./div.c:10
/mnt/f/DivideByZero/./div.c:11
/mnt/f/DivideByZero/./div.c:12
83: f7 7d f8 idivl -0x8(%rbp)
/mnt/f/DivideByZero/./div.c:13
■不適切なゼロ除算回避処理例
(warning): Either the condition ‘y==0’ is redundant or there is division by zero at line 3.
警告:ゼロ除算後のガード処理は無駄
[(warning)zerodivcond]
#include <stdio.h>
int div(int x,int y) {
int ret = x/y;
if(y == 0){ //ゼロ除算回避?
return 0;
}
return ret;
}
int main(void) {
printf("%d\n",div(3,0)) ;
}
x/yを実行する前に
if(y== 0)でゼロ除算回避してください。
参考:
INT33-C. 除算および剰余演算がゼロ除算エラーを引き起こさないことを保証する
https://www.jpcert.or.jp/sc-rules/c-int33-c.html