Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/crypto/strike_register.h" | 5 #include "net/quic/crypto/strike_register.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
| 12 | 12 |
| 13 namespace { | 13 namespace { |
| 14 | 14 |
| 15 using net::StrikeRegister; | 15 using net::StrikeRegister; |
| 16 using std::set; | 16 using std::set; |
| 17 using std::string; | 17 using std::string; |
| 18 | 18 |
| 19 const uint8 kOrbit[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; | 19 const uint8 kOrbit[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; |
| 20 | 20 |
| 21 void | 21 void |
| 22 NonceSetTimeAndOrbit(uint8 nonce[32], unsigned time, const uint8 orbit[8]) { | 22 NonceSetTimeAndOrbit(uint8 nonce[32], unsigned time, const uint8 orbit[8]) { |
|
wtc
2013/06/03 17:24:00
It is a little surprising that a function named
"s
ramant (doing other things)
2013/06/14 03:26:16
Fixed in CL: https://codereview.chromium.org/17040
| |
| 23 nonce[0] = time >> 24; | 23 nonce[0] = time >> 24; |
| 24 nonce[1] = time >> 16; | 24 nonce[1] = time >> 16; |
| 25 nonce[2] = time >> 8; | 25 nonce[2] = time >> 8; |
| 26 nonce[3] = time; | 26 nonce[3] = time; |
| 27 memcpy(nonce + 4, orbit, 8); | 27 memcpy(nonce + 4, orbit, 8); |
| 28 memset(nonce + 12, 0, 20); | |
| 28 } | 29 } |
| 29 | 30 |
| 30 TEST(StrikeRegisterTest, SimpleHorizon) { | 31 TEST(StrikeRegisterTest, SimpleHorizon) { |
| 31 // The set must reject values created on or before its own creation time. | 32 // The set must reject values created on or before its own creation time. |
| 32 StrikeRegister set(10 /* max size */, 1000 /* current time */, | 33 StrikeRegister set(10 /* max size */, 1000 /* current time */, |
| 33 100 /* window secs */, kOrbit); | 34 100 /* window secs */, kOrbit, |
| 35 StrikeRegister::DENY_REQUESTS_AT_STARTUP); | |
| 34 uint8 nonce[32]; | 36 uint8 nonce[32]; |
| 35 NonceSetTimeAndOrbit(nonce, 999, kOrbit); | 37 NonceSetTimeAndOrbit(nonce, 999, kOrbit); |
| 36 ASSERT_FALSE(set.Insert(nonce, 1000)); | 38 ASSERT_FALSE(set.Insert(nonce, 1000)); |
| 37 NonceSetTimeAndOrbit(nonce, 1000, kOrbit); | 39 NonceSetTimeAndOrbit(nonce, 1000, kOrbit); |
| 38 ASSERT_FALSE(set.Insert(nonce, 1000)); | 40 ASSERT_FALSE(set.Insert(nonce, 1000)); |
| 39 } | 41 } |
| 40 | 42 |
| 43 TEST(StrikeRegisterTest, NoStartupMode) { | |
| 44 // Check that a strike register works immediately if NO_STARTUP_PERIOD_NEEDED | |
| 45 // is specified. | |
| 46 StrikeRegister set(10 /* max size */, 0 /* current time */, | |
| 47 100 /* window secs */, kOrbit, | |
| 48 StrikeRegister::NO_STARTUP_PERIOD_NEEDED); | |
| 49 uint8 nonce[32]; | |
| 50 NonceSetTimeAndOrbit(nonce, 0, kOrbit); | |
| 51 ASSERT_TRUE(set.Insert(nonce, 0)); | |
| 52 ASSERT_FALSE(set.Insert(nonce, 0)); | |
| 53 } | |
| 54 | |
| 41 TEST(StrikeRegisterTest, WindowFuture) { | 55 TEST(StrikeRegisterTest, WindowFuture) { |
| 42 // The set must reject values outside the window. | 56 // The set must reject values outside the window. |
| 43 StrikeRegister set(10 /* max size */, 1000 /* current time */, | 57 StrikeRegister set(10 /* max size */, 1000 /* current time */, |
| 44 100 /* window secs */, kOrbit); | 58 100 /* window secs */, kOrbit, |
| 59 StrikeRegister::DENY_REQUESTS_AT_STARTUP); | |
| 45 uint8 nonce[32]; | 60 uint8 nonce[32]; |
| 46 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); | 61 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); |
| 47 ASSERT_FALSE(set.Insert(nonce, 1000)); | 62 ASSERT_FALSE(set.Insert(nonce, 1000)); |
| 48 NonceSetTimeAndOrbit(nonce, 999, kOrbit); | 63 NonceSetTimeAndOrbit(nonce, 999, kOrbit); |
| 49 ASSERT_FALSE(set.Insert(nonce, 1100)); | 64 ASSERT_FALSE(set.Insert(nonce, 1100)); |
| 50 } | 65 } |
| 51 | 66 |
| 52 TEST(StrikeRegisterTest, BadOrbit) { | 67 TEST(StrikeRegisterTest, BadOrbit) { |
| 53 // The set must reject values with the wrong orbit | 68 // The set must reject values with the wrong orbit |
| 54 StrikeRegister set(10 /* max size */, 1000 /* current time */, | 69 StrikeRegister set(10 /* max size */, 1000 /* current time */, |
| 55 100 /* window secs */, kOrbit); | 70 100 /* window secs */, kOrbit, |
| 71 StrikeRegister::DENY_REQUESTS_AT_STARTUP); | |
| 56 uint8 nonce[32]; | 72 uint8 nonce[32]; |
| 57 static const uint8 kBadOrbit[8] = { 0, 0, 0, 0, 1, 1, 1, 1 }; | 73 static const uint8 kBadOrbit[8] = { 0, 0, 0, 0, 1, 1, 1, 1 }; |
| 58 NonceSetTimeAndOrbit(nonce, 1101, kBadOrbit); | 74 NonceSetTimeAndOrbit(nonce, 1101, kBadOrbit); |
| 59 ASSERT_FALSE(set.Insert(nonce, 1100)); | 75 ASSERT_FALSE(set.Insert(nonce, 1100)); |
| 60 } | 76 } |
| 61 | 77 |
| 62 TEST(StrikeRegisterTest, OneValue) { | 78 TEST(StrikeRegisterTest, OneValue) { |
| 63 StrikeRegister set(10 /* max size */, 1000 /* current time */, | 79 StrikeRegister set(10 /* max size */, 1000 /* current time */, |
| 64 100 /* window secs */, kOrbit); | 80 100 /* window secs */, kOrbit, |
| 81 StrikeRegister::DENY_REQUESTS_AT_STARTUP); | |
| 65 uint8 nonce[32]; | 82 uint8 nonce[32]; |
| 66 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); | 83 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); |
| 67 ASSERT_TRUE(set.Insert(nonce, 1100)); | 84 ASSERT_TRUE(set.Insert(nonce, 1100)); |
| 68 } | 85 } |
| 69 | 86 |
| 70 TEST(StrikeRegisterTest, RejectDuplicate) { | 87 TEST(StrikeRegisterTest, RejectDuplicate) { |
| 71 // The set must reject values with the wrong orbit | 88 // The set must reject values with the wrong orbit |
| 72 StrikeRegister set(10 /* max size */, 1000 /* current time */, | 89 StrikeRegister set(10 /* max size */, 1000 /* current time */, |
| 73 100 /* window secs */, kOrbit); | 90 100 /* window secs */, kOrbit, |
| 91 StrikeRegister::DENY_REQUESTS_AT_STARTUP); | |
| 74 uint8 nonce[32]; | 92 uint8 nonce[32]; |
| 75 memset(nonce, 0, sizeof(nonce)); | 93 memset(nonce, 0, sizeof(nonce)); |
| 76 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); | 94 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); |
| 77 ASSERT_TRUE(set.Insert(nonce, 1100)); | 95 ASSERT_TRUE(set.Insert(nonce, 1100)); |
| 78 ASSERT_FALSE(set.Insert(nonce, 1100)); | 96 ASSERT_FALSE(set.Insert(nonce, 1100)); |
| 79 } | 97 } |
| 80 | 98 |
| 81 TEST(StrikeRegisterTest, HorizonUpdating) { | 99 TEST(StrikeRegisterTest, HorizonUpdating) { |
| 82 StrikeRegister set(5 /* max size */, 1000 /* current time */, | 100 StrikeRegister set(5 /* max size */, 1000 /* current time */, |
| 83 100 /* window secs */, kOrbit); | 101 100 /* window secs */, kOrbit, |
| 102 StrikeRegister::DENY_REQUESTS_AT_STARTUP); | |
| 84 uint8 nonce[6][32]; | 103 uint8 nonce[6][32]; |
| 85 for (unsigned i = 0; i < 5; i++) { | 104 for (unsigned i = 0; i < 5; i++) { |
| 86 NonceSetTimeAndOrbit(nonce[i], 1101, kOrbit); | 105 NonceSetTimeAndOrbit(nonce[i], 1101, kOrbit); |
| 87 memset(nonce[i] + 12, 0, 20); | 106 memset(nonce[i] + 12, 0, 20); |
| 88 nonce[i][31] = i; | 107 nonce[i][31] = i; |
| 89 ASSERT_TRUE(set.Insert(nonce[i], 1100)); | 108 ASSERT_TRUE(set.Insert(nonce[i], 1100)); |
| 90 } | 109 } |
| 91 | 110 |
| 92 // This should push the oldest value out and force the horizon to be updated. | 111 // This should push the oldest value out and force the horizon to be updated. |
| 93 NonceSetTimeAndOrbit(nonce[5], 1102, kOrbit); | 112 NonceSetTimeAndOrbit(nonce[5], 1102, kOrbit); |
| 94 memset(nonce[5] + 12, 0, 20); | 113 memset(nonce[5] + 12, 0, 20); |
| 95 ASSERT_TRUE(set.Insert(nonce[5], 1100)); | 114 ASSERT_TRUE(set.Insert(nonce[5], 1100)); |
| 96 | 115 |
| 97 // This should be behind the horizon now: | 116 // This should be behind the horizon now: |
| 98 NonceSetTimeAndOrbit(nonce[5], 1101, kOrbit); | 117 NonceSetTimeAndOrbit(nonce[5], 1101, kOrbit); |
| 99 memset(nonce[5] + 12, 0, 20); | 118 memset(nonce[5] + 12, 0, 20); |
| 100 nonce[5][31] = 10; | 119 nonce[5][31] = 10; |
| 101 ASSERT_FALSE(set.Insert(nonce[5], 1100)); | 120 ASSERT_FALSE(set.Insert(nonce[5], 1100)); |
| 102 } | 121 } |
| 103 | 122 |
| 104 TEST(StrikeRegisterTest, InsertMany) { | 123 TEST(StrikeRegisterTest, InsertMany) { |
| 105 StrikeRegister set(5000 /* max size */, 1000 /* current time */, | 124 StrikeRegister set(5000 /* max size */, 1000 /* current time */, |
| 106 500 /* window secs */, kOrbit); | 125 500 /* window secs */, kOrbit, |
| 126 StrikeRegister::DENY_REQUESTS_AT_STARTUP); | |
| 107 | 127 |
| 108 uint8 nonce[32]; | 128 uint8 nonce[32]; |
| 109 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); | 129 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); |
| 110 for (unsigned i = 0; i < 100000; i++) { | 130 for (unsigned i = 0; i < 100000; i++) { |
| 111 NonceSetTimeAndOrbit(nonce, 1101 + i/500, kOrbit); | 131 NonceSetTimeAndOrbit(nonce, 1101 + i/500, kOrbit); |
| 112 memcpy(nonce + 12, &i, sizeof(i)); | 132 memcpy(nonce + 12, &i, sizeof(i)); |
| 113 set.Insert(nonce, 1100); | 133 set.Insert(nonce, 1100); |
| 114 } | 134 } |
| 115 } | 135 } |
| 116 | 136 |
| 117 | 137 |
| 118 // For the following test we create a slow, but simple, version of a | 138 // For the following test we create a slow, but simple, version of a |
| 119 // StrikeRegister. The behaviour of this object is much easier to understand | 139 // StrikeRegister. The behaviour of this object is much easier to understand |
| 120 // than the fully fledged version. We then create a test to show, empirically, | 140 // than the fully fledged version. We then create a test to show, empirically, |
| 121 // that the two objects have identical behaviour. | 141 // that the two objects have identical behaviour. |
| 122 | 142 |
| 123 // A SlowStrikeRegister has the same public interface as a StrikeRegister, but | 143 // A SlowStrikeRegister has the same public interface as a StrikeRegister, but |
| 124 // is much slower. Hopefully it is also more obviously correct and we can | 144 // is much slower. Hopefully it is also more obviously correct and we can |
| 125 // empirically test that their behaviours are identical. | 145 // empirically test that their behaviours are identical. |
| 126 class SlowStrikeRegister { | 146 class SlowStrikeRegister { |
| 127 public: | 147 public: |
| 128 SlowStrikeRegister(unsigned max_entries, uint32 current_time, | 148 SlowStrikeRegister(unsigned max_entries, uint32 current_time, |
| 129 uint32 window_secs, const uint8 orbit[8]) | 149 uint32 window_secs, const uint8 orbit[8]) |
| 130 : max_entries_(max_entries), | 150 : max_entries_(max_entries), |
| 131 window_secs_(window_secs), | 151 window_secs_(window_secs), |
| 132 horizon_(current_time + window_secs) { | 152 creation_time_(current_time), |
| 153 horizon_(ExternalTimeToInternal(current_time + window_secs)) { | |
| 133 memcpy(orbit_, orbit, sizeof(orbit_)); | 154 memcpy(orbit_, orbit, sizeof(orbit_)); |
| 134 } | 155 } |
| 135 | 156 |
| 136 bool Insert(const uint8 nonce_bytes[32], const uint32 current_time) { | 157 bool Insert(const uint8 nonce_bytes[32], const uint32 current_time_external) { |
| 137 // Same overflow and underflow check as the real StrikeRegister. | 158 const uint32 current_time = ExternalTimeToInternal(current_time_external); |
| 138 if (current_time < window_secs_ || | |
| 139 current_time + window_secs_ < current_time) { | |
| 140 nonces_.clear(); | |
| 141 horizon_ = current_time; | |
| 142 return false; | |
| 143 } | |
| 144 | 159 |
| 145 // Check to see if the orbit is correct. | 160 // Check to see if the orbit is correct. |
| 146 if (memcmp(nonce_bytes + 4, orbit_, sizeof(orbit_))) { | 161 if (memcmp(nonce_bytes + 4, orbit_, sizeof(orbit_))) { |
| 147 return false; | 162 return false; |
| 148 } | 163 } |
| 149 const uint32 nonce_time = TimeFromBytes(nonce_bytes); | 164 const uint32 nonce_time = |
| 165 ExternalTimeToInternal(TimeFromBytes(nonce_bytes)); | |
| 150 // We have dropped one or more nonces with a time value of |horizon_|, so | 166 // We have dropped one or more nonces with a time value of |horizon_|, so |
| 151 // we have to reject anything with a timestamp less than or equal to that. | 167 // we have to reject anything with a timestamp less than or equal to that. |
| 152 if (nonce_time <= horizon_) { | 168 if (nonce_time <= horizon_) { |
| 153 return false; | 169 return false; |
| 154 } | 170 } |
| 155 | 171 |
| 156 // Check that the timestamp is in the current window. | 172 // Check that the timestamp is in the current window. |
| 157 if (nonce_time < (current_time - window_secs_) || | 173 if ((current_time > window_secs_ && |
| 174 nonce_time < (current_time - window_secs_)) || | |
| 158 nonce_time > (current_time + window_secs_)) { | 175 nonce_time > (current_time + window_secs_)) { |
| 159 return false; | 176 return false; |
| 160 } | 177 } |
| 161 | 178 |
| 162 const string nonce(reinterpret_cast<const char*>(nonce_bytes), 32); | 179 string nonce; |
| 180 nonce.reserve(32); | |
| 181 nonce += | |
| 182 string(reinterpret_cast<const char*>(&nonce_time), sizeof(nonce_time)); | |
| 183 nonce += | |
| 184 string(reinterpret_cast<const char*>(nonce_bytes) + sizeof(nonce_time), | |
| 185 32 - sizeof(nonce_time)); | |
| 163 | 186 |
| 164 set<string>::const_iterator it = nonces_.find(nonce); | 187 set<string>::const_iterator it = nonces_.find(nonce); |
| 165 if (it != nonces_.end()) { | 188 if (it != nonces_.end()) { |
| 166 return false; | 189 return false; |
| 167 } | 190 } |
| 168 | 191 |
| 169 if (nonces_.size() == max_entries_) { | 192 if (nonces_.size() == max_entries_) { |
| 170 DropOldestEntry(); | 193 DropOldestEntry(); |
| 171 } | 194 } |
| 172 | 195 |
| 173 nonces_.insert(nonce); | 196 nonces_.insert(nonce); |
| 174 return true; | 197 return true; |
| 175 } | 198 } |
| 176 | 199 |
| 177 private: | 200 private: |
| 178 // TimeFromBytes returns a big-endian uint32 from |d|. | 201 // TimeFromBytes returns a big-endian uint32 from |d|. |
| 179 static uint32 TimeFromBytes(const uint8 d[4]) { | 202 static uint32 TimeFromBytes(const uint8 d[4]) { |
| 180 return static_cast<uint32>(d[0]) << 24 | | 203 return static_cast<uint32>(d[0]) << 24 | |
| 181 static_cast<uint32>(d[1]) << 16 | | 204 static_cast<uint32>(d[1]) << 16 | |
| 182 static_cast<uint32>(d[2]) << 8 | | 205 static_cast<uint32>(d[2]) << 8 | |
| 183 static_cast<uint32>(d[3]); | 206 static_cast<uint32>(d[3]); |
| 184 } | 207 } |
| 185 | 208 |
| 209 uint32 ExternalTimeToInternal(uint32 external_time) { | |
| 210 static const uint32 kCreationTimeFromInternalEpoch = 63115200.0; | |
| 211 uint32 internal_epoch = 0; | |
| 212 if (creation_time_ > kCreationTimeFromInternalEpoch) { | |
| 213 internal_epoch = creation_time_ - kCreationTimeFromInternalEpoch; | |
| 214 } | |
| 215 | |
| 216 return external_time - internal_epoch; | |
| 217 } | |
| 218 | |
| 186 void DropOldestEntry() { | 219 void DropOldestEntry() { |
| 187 set<string>::iterator oldest = nonces_.begin(), it; | 220 set<string>::iterator oldest = nonces_.begin(), it; |
| 188 uint32 oldest_time = | 221 uint32 oldest_time = |
| 189 TimeFromBytes(reinterpret_cast<const uint8*>(oldest->data())); | 222 TimeFromBytes(reinterpret_cast<const uint8*>(oldest->data())); |
| 190 | 223 |
| 191 for (it = oldest; it != nonces_.end(); it++) { | 224 for (it = oldest; it != nonces_.end(); it++) { |
| 192 uint32 t = TimeFromBytes(reinterpret_cast<const uint8*>(it->data())); | 225 uint32 t = TimeFromBytes(reinterpret_cast<const uint8*>(it->data())); |
| 193 if (t < oldest_time || | 226 if (t < oldest_time || |
| 194 (t == oldest_time && memcmp(it->data(), oldest->data(), 32) < 0)) { | 227 (t == oldest_time && memcmp(it->data(), oldest->data(), 32) < 0)) { |
| 195 oldest_time = t; | 228 oldest_time = t; |
| 196 oldest = it; | 229 oldest = it; |
| 197 } | 230 } |
| 198 } | 231 } |
| 199 | 232 |
| 200 nonces_.erase(oldest); | 233 nonces_.erase(oldest); |
| 201 horizon_ = oldest_time; | 234 horizon_ = oldest_time; |
| 202 } | 235 } |
| 203 | 236 |
| 204 const unsigned max_entries_; | 237 const unsigned max_entries_; |
| 205 const unsigned window_secs_; | 238 const unsigned window_secs_; |
| 239 const uint32 creation_time_; | |
| 206 uint8 orbit_[8]; | 240 uint8 orbit_[8]; |
| 207 uint32 horizon_; | 241 uint32 horizon_; |
| 208 | 242 |
| 209 set<string> nonces_; | 243 set<string> nonces_; |
| 210 }; | 244 }; |
| 211 | 245 |
| 212 TEST(StrikeRegisterStressTest, Stress) { | 246 TEST(StrikeRegisterStressTest, Stress) { |
| 213 // Fixed seed gives reproducibility for this test. | 247 // Fixed seed gives reproducibility for this test. |
| 214 srand(42); | 248 srand(42); |
| 215 unsigned max_entries = 64; | 249 unsigned max_entries = 64; |
| 216 uint32 current_time = 10000, window = 200; | 250 uint32 current_time = 10000, window = 200; |
| 217 scoped_ptr<StrikeRegister> s1( | 251 scoped_ptr<StrikeRegister> s1( |
| 218 new StrikeRegister(max_entries, current_time, window, kOrbit)); | 252 new StrikeRegister(max_entries, current_time, window, kOrbit, |
| 253 StrikeRegister::DENY_REQUESTS_AT_STARTUP)); | |
| 219 scoped_ptr<SlowStrikeRegister> s2( | 254 scoped_ptr<SlowStrikeRegister> s2( |
| 220 new SlowStrikeRegister(max_entries, current_time, window, kOrbit)); | 255 new SlowStrikeRegister(max_entries, current_time, window, kOrbit)); |
| 221 uint64 i; | 256 uint64 i; |
| 222 | 257 |
| 223 // When making changes it's worth removing the limit on this test and running | 258 // When making changes it's worth removing the limit on this test and running |
| 224 // it for a while. For the initial development an opt binary was left running | 259 // it for a while. For the initial development an opt binary was left running |
| 225 // for 10 minutes. | 260 // for 10 minutes. |
| 226 const uint64 kMaxIterations = 10000; | 261 const uint64 kMaxIterations = 10000; |
| 227 for (i = 0; i < kMaxIterations; i++) { | 262 for (i = 0; i < kMaxIterations; i++) { |
| 228 if (rand() % 1000 == 0) { | 263 if (rand() % 1000 == 0) { |
| 229 // 0.1% chance of resetting the sets. | 264 // 0.1% chance of resetting the sets. |
| 230 max_entries = rand() % 300 + 2; | 265 max_entries = rand() % 300 + 2; |
| 231 current_time = rand() % 10000; | 266 current_time = rand() % 10000; |
| 232 window = rand() % 500; | 267 window = rand() % 500; |
| 233 s1.reset(new StrikeRegister(max_entries, current_time, window, kOrbit)); | 268 s1.reset(new StrikeRegister(max_entries, current_time, window, kOrbit, |
| 269 StrikeRegister::DENY_REQUESTS_AT_STARTUP)); | |
| 234 s2.reset( | 270 s2.reset( |
| 235 new SlowStrikeRegister(max_entries, current_time, window, kOrbit)); | 271 new SlowStrikeRegister(max_entries, current_time, window, kOrbit)); |
| 236 } | 272 } |
| 237 | 273 |
| 238 int32 time_delta = rand() % (window * 4); | 274 int32 time_delta = rand() % (window * 4); |
| 239 time_delta -= window * 2; | 275 time_delta -= window * 2; |
| 240 const uint32 time = current_time + time_delta; | 276 const uint32 time = current_time + time_delta; |
| 241 if (time_delta < 0 && time > current_time) { | 277 if (time_delta < 0 && time > current_time) { |
| 242 continue; // overflow | 278 continue; // overflow |
| 243 } | 279 } |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 262 s1->Validate(); | 298 s1->Validate(); |
| 263 } | 299 } |
| 264 } | 300 } |
| 265 | 301 |
| 266 if (i != kMaxIterations) { | 302 if (i != kMaxIterations) { |
| 267 FAIL() << "Failed after " << i << " iterations"; | 303 FAIL() << "Failed after " << i << " iterations"; |
| 268 } | 304 } |
| 269 } | 305 } |
| 270 | 306 |
| 271 } // anonymous namespace | 307 } // anonymous namespace |
| OLD | NEW |