Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Side by Side Diff: base/time/time_posix.cc

Issue 2405453002: Fix Integer-overflow in base::Time::FromExploded. (Closed)
Patch Set: rebased and fixed net unittest Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/time/time_mac.cc ('k') | base/time/time_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "base/time/time.h" 5 #include "base/time/time.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <sys/time.h> 8 #include <sys/time.h>
9 #include <time.h> 9 #include <time.h>
10 #if defined(OS_ANDROID) && !defined(__LP64__) 10 #if defined(OS_ANDROID) && !defined(__LP64__)
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 timestruct.tm_mon = exploded.month - 1; 235 timestruct.tm_mon = exploded.month - 1;
236 timestruct.tm_year = exploded.year - 1900; 236 timestruct.tm_year = exploded.year - 1900;
237 timestruct.tm_wday = exploded.day_of_week; // mktime/timegm ignore this 237 timestruct.tm_wday = exploded.day_of_week; // mktime/timegm ignore this
238 timestruct.tm_yday = 0; // mktime/timegm ignore this 238 timestruct.tm_yday = 0; // mktime/timegm ignore this
239 timestruct.tm_isdst = -1; // attempt to figure it out 239 timestruct.tm_isdst = -1; // attempt to figure it out
240 #if !defined(OS_NACL) && !defined(OS_SOLARIS) 240 #if !defined(OS_NACL) && !defined(OS_SOLARIS)
241 timestruct.tm_gmtoff = 0; // not a POSIX field, so mktime/timegm ignore 241 timestruct.tm_gmtoff = 0; // not a POSIX field, so mktime/timegm ignore
242 timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore 242 timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore
243 #endif 243 #endif
244 244
245 int64_t milliseconds;
246 SysTime seconds; 245 SysTime seconds;
247 246
248 // Certain exploded dates do not really exist due to daylight saving times, 247 // Certain exploded dates do not really exist due to daylight saving times,
249 // and this causes mktime() to return implementation-defined values when 248 // and this causes mktime() to return implementation-defined values when
250 // tm_isdst is set to -1. On Android, the function will return -1, while the 249 // tm_isdst is set to -1. On Android, the function will return -1, while the
251 // C libraries of other platforms typically return a liberally-chosen value. 250 // C libraries of other platforms typically return a liberally-chosen value.
252 // Handling this requires the special code below. 251 // Handling this requires the special code below.
253 252
254 // SysTimeFromTimeStruct() modifies the input structure, save current value. 253 // SysTimeFromTimeStruct() modifies the input structure, save current value.
255 struct tm timestruct0 = timestruct; 254 struct tm timestruct0 = timestruct;
(...skipping 17 matching lines...) Expand all
273 else if (seconds_isdst1 < 0) 272 else if (seconds_isdst1 < 0)
274 seconds = seconds_isdst0; 273 seconds = seconds_isdst0;
275 else 274 else
276 seconds = std::min(seconds_isdst0, seconds_isdst1); 275 seconds = std::min(seconds_isdst0, seconds_isdst1);
277 } 276 }
278 277
279 // Handle overflow. Clamping the range to what mktime and timegm might 278 // Handle overflow. Clamping the range to what mktime and timegm might
280 // return is the best that can be done here. It's not ideal, but it's better 279 // return is the best that can be done here. It's not ideal, but it's better
281 // than failing here or ignoring the overflow case and treating each time 280 // than failing here or ignoring the overflow case and treating each time
282 // overflow as one second prior to the epoch. 281 // overflow as one second prior to the epoch.
282 int64_t milliseconds = 0;
283 if (seconds == -1 && 283 if (seconds == -1 &&
284 (exploded.year < 1969 || exploded.year > 1970)) { 284 (exploded.year < 1969 || exploded.year > 1970)) {
285 // If exploded.year is 1969 or 1970, take -1 as correct, with the 285 // If exploded.year is 1969 or 1970, take -1 as correct, with the
286 // time indicating 1 second prior to the epoch. (1970 is allowed to handle 286 // time indicating 1 second prior to the epoch. (1970 is allowed to handle
287 // time zone and DST offsets.) Otherwise, return the most future or past 287 // time zone and DST offsets.) Otherwise, return the most future or past
288 // time representable. Assumes the time_t epoch is 1970-01-01 00:00:00 UTC. 288 // time representable. Assumes the time_t epoch is 1970-01-01 00:00:00 UTC.
289 // 289 //
290 // The minimum and maximum representible times that mktime and timegm could 290 // The minimum and maximum representible times that mktime and timegm could
291 // return are used here instead of values outside that range to allow for 291 // return are used here instead of values outside that range to allow for
292 // proper round-tripping between exploded and counter-type time 292 // proper round-tripping between exploded and counter-type time
(...skipping 12 matching lines...) Expand all
305 const int64_t max_seconds = (sizeof(SysTime) < sizeof(int64_t)) 305 const int64_t max_seconds = (sizeof(SysTime) < sizeof(int64_t))
306 ? std::numeric_limits<SysTime>::max() 306 ? std::numeric_limits<SysTime>::max()
307 : std::numeric_limits<int32_t>::max(); 307 : std::numeric_limits<int32_t>::max();
308 if (exploded.year < 1969) { 308 if (exploded.year < 1969) {
309 milliseconds = min_seconds * kMillisecondsPerSecond; 309 milliseconds = min_seconds * kMillisecondsPerSecond;
310 } else { 310 } else {
311 milliseconds = max_seconds * kMillisecondsPerSecond; 311 milliseconds = max_seconds * kMillisecondsPerSecond;
312 milliseconds += (kMillisecondsPerSecond - 1); 312 milliseconds += (kMillisecondsPerSecond - 1);
313 } 313 }
314 } else { 314 } else {
315 milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond; 315 base::CheckedNumeric<int64_t> checked_millis = seconds;
316 checked_millis *= kMillisecondsPerSecond;
317 checked_millis += exploded.millisecond;
318 if (!checked_millis.IsValid()) {
319 *time = base::Time(0);
320 return false;
321 }
322 milliseconds = checked_millis.ValueOrDie();
316 } 323 }
317 324
318 // Adjust from Unix (1970) to Windows (1601) epoch. 325 // Adjust from Unix (1970) to Windows (1601) epoch avoiding overflows.
319 base::Time converted_time = 326 base::CheckedNumeric<int64_t> checked_microseconds_win_epoch = milliseconds;
320 Time((milliseconds * kMicrosecondsPerMillisecond) + 327 checked_microseconds_win_epoch *= kMicrosecondsPerMillisecond;
321 kWindowsEpochDeltaMicroseconds); 328 checked_microseconds_win_epoch += kWindowsEpochDeltaMicroseconds;
329 if (!checked_microseconds_win_epoch.IsValid()) {
330 *time = base::Time(0);
331 return false;
332 }
333 base::Time converted_time(checked_microseconds_win_epoch.ValueOrDie());
322 334
323 // If |exploded.day_of_month| is set to 31 on a 28-30 day month, it will 335 // If |exploded.day_of_month| is set to 31 on a 28-30 day month, it will
324 // return the first day of the next month. Thus round-trip the time and 336 // return the first day of the next month. Thus round-trip the time and
325 // compare the initial |exploded| with |utc_to_exploded| time. 337 // compare the initial |exploded| with |utc_to_exploded| time.
326 base::Time::Exploded to_exploded; 338 base::Time::Exploded to_exploded;
327 if (!is_local) 339 if (!is_local)
328 converted_time.UTCExplode(&to_exploded); 340 converted_time.UTCExplode(&to_exploded);
329 else 341 else
330 converted_time.LocalExplode(&to_exploded); 342 converted_time.LocalExplode(&to_exploded);
331 343
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1; 409 result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
398 return result; 410 return result;
399 } 411 }
400 int64_t us = us_ - kTimeTToMicrosecondsOffset; 412 int64_t us = us_ - kTimeTToMicrosecondsOffset;
401 result.tv_sec = us / Time::kMicrosecondsPerSecond; 413 result.tv_sec = us / Time::kMicrosecondsPerSecond;
402 result.tv_usec = us % Time::kMicrosecondsPerSecond; 414 result.tv_usec = us % Time::kMicrosecondsPerSecond;
403 return result; 415 return result;
404 } 416 }
405 417
406 } // namespace base 418 } // namespace base
OLDNEW
« no previous file with comments | « base/time/time_mac.cc ('k') | base/time/time_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698