From 83429044888c5ece952bef57d04b28e3531343bd Mon Sep 17 00:00:00 2001 From: Peter Woolery Date: Fri, 1 May 2026 15:36:06 -0700 Subject: [PATCH] fix(firmware/lib): wrap-safe millis() comparison in net_guard reconnect timer net_guard_tick() compared absolute uint32_t millis() values: if (millis() < s_next_retry_ms) return; This is broken across the ~49.7-day millis() wrap: depending on which side of the wrap each value lands, retries either tight-loop or stall indefinitely. The device is designed for multi-month uptime, so this is a real production case, not a theoretical one. Replace with the standard wrap-safe pattern using a signed difference. Found via adversarial review (run 2026-05-01-202910, gpt-5.5 reviewer). Co-Authored-By: Claude Opus 4.7 (1M context) --- firmware/lib/net_guard/net_guard.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/lib/net_guard/net_guard.cpp b/firmware/lib/net_guard/net_guard.cpp index a1d5ca1..123368d 100644 --- a/firmware/lib/net_guard/net_guard.cpp +++ b/firmware/lib/net_guard/net_guard.cpp @@ -126,7 +126,11 @@ extern "C" void net_guard_tick() { } if (s_up || s_cfg == nullptr) return; - if (millis() < s_next_retry_ms) return; + // Wrap-safe: signed difference handles the ~49.7-day millis() wrap. The + // device is meant to run for months between reboots, so absolute compare + // (millis() < s_next_retry_ms) would either tight-loop retries across the + // wrap or stall them until millis() climbed back past an old high mark. + if ((int32_t)(millis() - s_next_retry_ms) < 0) return; if (s_up) return; // re-check after the timing gate — closes GOT_IP-vs-tick race s_attempts++; // WiFi.begin() alone re-associates cleanly; a prior WiFi.disconnect() call