test(runner): volatile-qualify setjmp loop index for -Wclobbered-clean build (bf-2k3o)

The per-test loop in main() spans the setjmp(g_test_jmp)/longjmp recovery
target: i is read (loop test + increment) on the longjmp-return path. gcc's
-Wclobbered (enabled under -Wall) flags exactly this loop-index-across-setjmp
shape. The build was clean today only coincidentally — the preceding qsort()
call biases gcc's register heuristic; an identical loop without it warns at
-O1/-O2 (verified). Qualify i as volatile per C11 7.13.2.1, the sanctioned
remedy (no pragma, no flag downgrade), with no behavior change. This is the
compile-cleanliness gate for the guard (parent bf-22vg).

Verified: gcc -std=c11 -Wall -Wextra -Wclobbered -Werror is clean at
-O0/-O1/-O2/-O3/-Os/-Og; make -C firmware/test test builds warning-free and
runs all 30 tests (exit 0). Only firmware/test/test_runner.c touched.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
jedarden 2026-07-03 21:11:50 -04:00
parent b62fa3ed60
commit 7b6a3d89b2

View file

@ -229,7 +229,21 @@ int main(void)
{
qsort(g_tests, (size_t)g_test_count, sizeof(g_tests[0]), test_entry_cmp);
for (int i = 0; i < g_test_count; i++) {
/*
* volatile is genuinely required, not cosmetic: i spans the setjmp/longjmp
* below and is read (the i < g_test_count test and the i++ advance) on the
* longjmp-return path, i.e. after control resumes here from a failed
* assertion. C11 7.13.2.1 makes a non-volatile automatic that has been
* changed between the setjmp and the longjmp indeterminate on return, and
* gcc's -Wclobbered (on under -Wall) flags exactly this loop-index-across-
* setjmp shape empirically the identical loop warns once the incidental
* preceding qsort() call stops biasing gcc's register heuristic. volatile
* exempts i from both the indeterminate rule and the warning, with no
* behavior change (the counter still walks 0..g_test_count-1). This is the
* compile-cleanliness gate for the guard (parent bf-22vg): no pragma and no
* flag downgrade, per C11 7.13.2.1's sanctioned remedy.
*/
for (volatile int i = 0; i < g_test_count; i++) {
/*
* The RUN line is the one observable line per test and prints BEFORE the
* setjmp, so it appears regardless of how the body ends. The body itself