diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index c1936e7a7d..8978fda08d 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -54,3 +54,15 @@ message = "Make certain types for EMR Serverless optional. Previously, they defa references = ["smithy-rs#3217"] meta = { "breaking" = true, "tada" = false, "bug" = true } author = "milesziemer" + +[[smithy-rs]] +message = "Prevent multiplication overflow in backoff computation" +references = ["smithy-rs#3229", "aws-sdk-rust#960"] +meta = { "breaking" = false, "tada" = false, "bug" = true, target = "client" } +author = "rcoh" + +[[aws-sdk-rust]] +message = "Prevent multiplication overflow in backoff computation" +references = ["smithy-rs#3229", "aws-sdk-rust#960"] +meta = { "breaking" = false, "tada" = false, "bug" = true } +author = "rcoh" diff --git a/rust-runtime/aws-smithy-runtime/src/client/retries/strategy/standard.rs b/rust-runtime/aws-smithy-runtime/src/client/retries/strategy/standard.rs index 98d1308831..de74b31c2b 100644 --- a/rust-runtime/aws-smithy-runtime/src/client/retries/strategy/standard.rs +++ b/rust-runtime/aws-smithy-runtime/src/client/retries/strategy/standard.rs @@ -286,7 +286,10 @@ fn check_rate_limiter_for_delay( } fn calculate_exponential_backoff(base: f64, initial_backoff: f64, retry_attempts: u32) -> f64 { - base * initial_backoff * 2_u32.pow(retry_attempts) as f64 + 2_u32 + .checked_pow(retry_attempts) + .map(|backoff| (backoff as f64) * base * initial_backoff) + .unwrap_or(f64::MAX) } fn get_seconds_since_unix_epoch(runtime_components: &RuntimeComponents) -> f64 { @@ -793,4 +796,13 @@ mod tests { assert_eq!(expected_backoff, actual_backoff); } } + + #[test] + fn calculate_backoff_overflow() { + // avoid overflow for a silly large amount of retry attempts + assert_eq!( + calculate_exponential_backoff(1_f64, 10_f64, 100000), + f64::MAX + ); + } }