the SAME bug at -O0 vs -O2. ------------------------------------------------------------ One null-store bug, compiled two ways, to show WHY you debug at -O0 -g: -O0 : every local is a real stack slot. gdb shows `scaled = 49`, the line table is 1:1 with the source, single-stepping is sane. -O2 : the optimizer folds `scaled` into a constant, may inline `crash_after_math` into main, and reorders code. gdb prints `<optimized out>` (or "No symbol") and the reported line jumps around. Compare the IR and asm at both levels: clang -g -O0 -S -emit-llvm opt_levels.c -o opt_O0.ll clang -g -O2 -S -emit-llvm opt_levels.c -o opt_O2.ll clang -g -O0 -S opt_levels.c -o opt_O0.s clang -g -O2 -S opt_levels.c -o opt_O2.s and watch gdb lose `scaled`: clang -g -O0 opt_levels.c -o opt_O0 ; clang -g -O2 opt_levels.c -o opt_O2 gdb -q -batch -ex 'break crash_after_math' -ex run -ex 'print scaled' ./opt_O0 gdb -q -batch -ex 'break crash_after_math' -ex run -ex 'print scaled' ./opt_O2 (REAL output in cross_level/README.md.) ============================================================
int crash_after_math(int *p, int a, int b) {
int scaled = a * b + 7; /* real local at -O0; constant-folded away at -O2 */
*p = scaled; /* faults when p == NULL */
return scaled;
}
int main(void) {
int *p = 0;
return crash_after_math(p, 6, 7); /* scaled = 6*7+7 = 49 */
}A lab is done when you can say what it showed on your machine — not when you have read it.
It decides which problems come first, which drills open, which labs you see and how the Learn surface is organised. Change it any time from the switch in the top bar, or press Escape to look around first.