FForge
← Labsdebug-03Runtime debugging●○○○

Integer divide by zero (SIGFPE)

debug/03_divzero.c3 steps
0/3 steps
evidence to leave with
x/i $pc shows idiv; UBSan names file:line:col
walk it, one step at a time
run this
$ clang -g -O0 03_divzero.c -o bin/03_divzero
$ ./bin/03_divzero ; echo "exit=$?"
what it printed on the machine that wrote this lab
computing 100 / 0 ...
Floating point exception (core dumped)
exit=136
run this
$ gdb -q -batch -ex 'set debuginfod enabled off' \
what it printed on the machine that wrote this lab
      -ex run -ex bt -ex 'print b' -ex 'info locals' \
      -ex 'x/i $pc' ./bin/03_divzero
Program received signal SIGFPE, Arithmetic exception.
0x00000000004004b1 in main (argc=1, argv=0x7fffffffd888) at 03_divzero.c:87
87      int q = a / b;            // <-- THE BUG
#0  0x00000000004004b1 in main (argc=1, argv=0x7fffffffd888) at 03_divzero.c:87
$1 = 0
a = 100
b = 0
q = 0
=> 0x4004b1 <main+65>:  idivl  -0x18(%rbp)
How to read each command:
  run         -> stops on SIGFPE, right at the faulting instruction.
  bt          -> the call stack; names main and 03_divzero.c:87.
  print b     -> b == 0: the divisor is the problem.
  info locals -> a=100, b=0, confirming the operands.
  x/i $pc     -> disassemble the faulting instruction: it is an `idiv`
                 (signed integer divide). Proof it's an INTEGER, not FP,
                 fault despite the "Floating point exception" wording.
run this
$ valgrind -q ./bin/03_divzero
what it printed on the machine that wrote this lab
  ==57274== Process terminating with default action of signal 8 (SIGFPE): dumping core
  ==57274==  Integer divide by zero at address 0x1002D8A124
  ==57274==    at 0x4004B1: main (03_divzero.c:87)
  valgrind/memcheck tracks MEMORY errors. A divide-by-zero is an arithmetic
  fault, not a bad memory access, so memcheck adds nothing — it just lets
  the SIGFPE through. Reach for a sanitizer instead:
run this
$ clang -g -O0 -fsanitize=undefined 03_divzero.c -o bin/03_divzero.ubsan
$ ./bin/03_divzero.ubsan ; echo "exit=$?"
what it printed on the machine that wrote this lab
  03_divzero.c:87:15: runtime error: division by zero
  SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior 03_divzero.c:87:15
  UndefinedBehaviorSanitizer:DEADLYSIGNAL
  ==57286==ERROR: UndefinedBehaviorSanitizer: FPE on unknown address 0x00000042dfae
      #0 0x42dfae in main debug_lab/03_divzero.c:87:15
  exit=1
  UBSan instruments the divide and prints the exact file:line:column and a
  plain-English "division by zero" BEFORE the hardware fault. This is the
  right tool for arithmetic UB.

ROOT CAUSE vs CRASH SITE: The crash site is the divide. The root cause is that `b` was allowed to become 0 (here: program run with no extra args -> argc-1 == 0). In real code, validate denominators at their SOURCE, not at the divide.

category

arithmetic fault (SIGFPE) / UB

difficulty

1 ------------------------------------------------------------

what's wrong

`a / b` is evaluated with b == 0. Integer division by zero is Undefined Behavior in C; on x86-64 the DIV/IDIV instruction raises a hardware exception (#DE), delivered as SIGFPE. Buggy line: `int q = a / b;`. (`b` comes from argc so the compiler can't fold it away and the divide really executes at runtime.)

symptom

"Floating point exception (core dumped)" — note the name is a misnomer: it is an INTEGER divide fault. Shell exit 136 (136 = 128 + 8 = 128 + SIGFPE). Deterministic.

the fix

Guard the divisor: if (b == 0) { fprintf(stderr, "denominator is zero\n"); return 1; } int q = a / b;

take it further

Run `./bin/03_divzero 5` (one arg => b==1). It prints q=100 and exits 0 — same code, no bug, because the input no longer drives b to 0. Bugs that depend on input are why you reproduce with the EXACT failing input. ============================================================

read the source · debug/03_divzero.c
#include <stdio.h> int main(int argc, char **argv) { int a = 100; int b = argc - 1; /* 0 when run with no extra args */ printf("computing %d / %d ...\n", a, b); int q = a / b; /* <-- THE BUG: divide by zero */ printf("q = %d\n", q); (void)argv; return 0; }
◇
Finish the lab: write the evidence note

A lab is done when you can say what it showed on your machine — not when you have read it.