Index: net/base/backoff_entry.cc |
diff --git a/net/base/backoff_entry.cc b/net/base/backoff_entry.cc |
index b1826b7af469b4d72cfccd6ad849173ceb1f24fe..0b3a06f1d559e181aa5fdd1157834b0384482ee6 100644 |
--- a/net/base/backoff_entry.cc |
+++ b/net/base/backoff_entry.cc |
@@ -8,7 +8,9 @@ |
#include <cmath> |
#include <limits> |
+#include "base/basictypes.h" |
#include "base/logging.h" |
+#include "base/numerics/safe_math.h" |
#include "base/rand_util.h" |
namespace net { |
@@ -132,22 +134,39 @@ base::TimeTicks BackoffEntry::CalculateReleaseTime() const { |
// The delay is calculated with this formula: |
// delay = initial_backoff * multiply_factor^( |
// effective_failure_count - 1) * Uniform(1 - jitter_factor, 1] |
- double delay = policy_->initial_delay_ms; |
- delay *= pow(policy_->multiply_factor, effective_failure_count - 1); |
- delay -= base::RandDouble() * policy_->jitter_factor * delay; |
- |
- const int64 kMaxInt64 = std::numeric_limits<int64>::max(); |
- int64 delay_int = (delay > kMaxInt64) ? |
- kMaxInt64 : static_cast<int64>(delay + 0.5); |
+ // Note: if the failure count is too high, |delay_ms| will become infinity |
+ // after the exponential calculation, and then NaN after the jitter is |
+ // accounted for. Both cases are handled by using CheckedNumeric<int64> to |
+ // perform the conversion to integers. |
+ double delay_ms = policy_->initial_delay_ms; |
+ delay_ms *= pow(policy_->multiply_factor, effective_failure_count - 1); |
+ delay_ms -= base::RandDouble() * policy_->jitter_factor * delay_ms; |
+ |
+ // Do overflow checking in microseconds, the internal unit of TimeTicks. |
+ const int64 kTimeTicksNowUs = |
+ (ImplGetTimeNow() - base::TimeTicks()).InMicroseconds(); |
+ base::internal::CheckedNumeric<int64> calculated_release_time_us = |
+ delay_ms + 0.5; |
+ calculated_release_time_us *= base::Time::kMicrosecondsPerMillisecond; |
+ calculated_release_time_us += kTimeTicksNowUs; |
+ |
+ base::internal::CheckedNumeric<int64> maximum_release_time_us = kint64max; |
+ if (policy_->maximum_backoff_ms >= 0) { |
+ maximum_release_time_us = policy_->maximum_backoff_ms; |
+ maximum_release_time_us *= base::Time::kMicrosecondsPerMillisecond; |
+ maximum_release_time_us += kTimeTicksNowUs; |
+ } |
- // Ensure that we do not exceed maximum delay. |
- if (policy_->maximum_backoff_ms >= 0) |
- delay_int = std::min(delay_int, policy_->maximum_backoff_ms); |
+ // Decide between maximum release time and calculated release time, accounting |
+ // for overflow with both. |
+ int64 release_time_us = std::min( |
+ calculated_release_time_us.ValueOrDefault(kint64max), |
+ maximum_release_time_us.ValueOrDefault(kint64max)); |
// Never reduce previously set release horizon, e.g. due to Retry-After |
// header. |
return std::max( |
- ImplGetTimeNow() + base::TimeDelta::FromMilliseconds(delay_int), |
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(release_time_us), |
exponential_backoff_release_time_); |
} |