From 7b6a3d89b27856ac3fc2e339fdfe3b79849c9f7b Mon Sep 17 00:00:00 2001 From: jedarden Date: Fri, 3 Jul 2026 21:11:50 -0400 Subject: [PATCH] test(runner): volatile-qualify setjmp loop index for -Wclobbered-clean build (bf-2k3o) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- firmware/test/test_runner.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/firmware/test/test_runner.c b/firmware/test/test_runner.c index 6583dec..219bb30 100644 --- a/firmware/test/test_runner.c +++ b/firmware/test/test_runner.c @@ -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