Chromium Code Reviews| Index: net/base/backoff_entry.cc |
| diff --git a/net/base/backoff_entry.cc b/net/base/backoff_entry.cc |
| index b1826b7af469b4d72cfccd6ad849173ceb1f24fe..f2753935620e20f662426a87bc79a82d82554a50 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,36 @@ 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); |
| - |
| - // Ensure that we do not exceed maximum delay. |
| - if (policy_->maximum_backoff_ms >= 0) |
| - delay_int = std::min(delay_int, policy_->maximum_backoff_ms); |
| + // 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> checked_release_time_us = |
|
cbentzel
2014/06/16 21:08:32
NaN to integer conversion is undefined, not sure i
Nicolas Zea
2014/06/17 00:33:29
CheckedNumeric, from my understanding of the code,
Ryan Sleevi
2014/06/17 20:02:12
I believe Nicolas is correct.
That is, it invokes
|
| + delay_ms + 0.5; |
| + checked_release_time_us *= base::Time::kMicrosecondsPerMillisecond; |
| + checked_release_time_us += kTimeTicksNowUs; |
| + |
| + // Ensure that we do not exceed maximum delay once overflow is accounted for. |
| + int64 release_time_us = (policy_->maximum_backoff_ms >= 0 |
| + ? kTimeTicksNowUs + |
| + base::Time::kMicrosecondsPerMillisecond * |
| + policy_->maximum_backoff_ms |
|
Ryan Sleevi
2014/06/16 22:12:47
Can't this still overflow?
Nicolas Zea
2014/06/17 00:33:29
Hmm, I suppose if a developer gives a massive/inva
Ryan Sleevi
2014/06/17 20:02:12
*shrug* I agree, it's likely an error in policy, b
Nicolas Zea
2014/06/17 21:31:43
Done.
|
| + : kint64max); |
| + release_time_us = |
| + std::min(checked_release_time_us.ValueOrDefault(release_time_us), |
| + release_time_us); |
| // 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), |
|
Ryan Sleevi
2014/06/16 22:12:47
Can't this still overflow?
Nicolas Zea
2014/06/17 00:33:29
base::TimeTicks() is a 0 value, this is just for c
|
| exponential_backoff_release_time_); |
| } |