From d76acde5febff682da0a41142d4a54a7e75f208d Mon Sep 17 00:00:00 2001 From: Eli Foster Date: Wed, 5 Aug 2026 16:43:12 -0700 Subject: [PATCH] fix(relay): avoid overflow when rounding microsecond timeouts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pg_timeout_millis rounded `us` values with `(value + 500) / 1_000`, which overflows for the top 500 representable u128 magnitudes — a debug panic during config load, or in release a wrapped near-zero millisecond value that slips past the range check and hands the original gigantic string to every pool's after_connect. Round without the intermediate, and cover u128::MAX and the first overflowing value in the fallback test. Co-Authored-By: Claude Opus 5 Signed-off-by: Eli Foster --- crates/buzz-relay/src/config.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/buzz-relay/src/config.rs b/crates/buzz-relay/src/config.rs index 67fae1260..6e739b015 100644 --- a/crates/buzz-relay/src/config.rs +++ b/crates/buzz-relay/src/config.rs @@ -312,7 +312,9 @@ fn parse_bind_addr(raw: &str) -> Result { fn pg_timeout_millis(magnitude: &str, unit: &str) -> Option { let value = magnitude.parse::().ok()?; match unit { - "us" => Some((value + 500) / 1_000), + // Round half up without the `value + 500` intermediate, which overflows + // for the top 500 representable microsecond values. + "us" => Some(value / 1_000 + u128::from(value % 1_000 >= 500)), "" | "ms" => Some(value), "s" => value.checked_mul(1_000), "min" => value.checked_mul(60_000), @@ -1378,6 +1380,11 @@ mod tests { // Wider than any integer type — must fall back, not overflow. "999999999999999999999999999999999999999999d", "99999999999999999999999999999999999999999999999999", + // Parses as u128, so unlike the two above it reaches the unit + // conversion — where rounding must not overflow on the way to the + // range check. + &format!("{}us", u128::MAX), + &format!("{}us", u128::MAX - 499), ] { assert_eq!( pg_timeout_or_default(Some(rejected), "30s"),