Index: base/time/time_posix.cc |
diff --git a/base/time/time_posix.cc b/base/time/time_posix.cc |
index ac0e99f7eb61b30de3eb16556f77869a8ee4704b..4caf3866c524fd886f24c750a13fd5a8157f2207 100644 |
--- a/base/time/time_posix.cc |
+++ b/base/time/time_posix.cc |
@@ -242,7 +242,6 @@ bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) { |
timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore |
#endif |
- int64_t milliseconds; |
SysTime seconds; |
// Certain exploded dates do not really exist due to daylight saving times, |
@@ -280,6 +279,7 @@ bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) { |
// return is the best that can be done here. It's not ideal, but it's better |
// than failing here or ignoring the overflow case and treating each time |
// overflow as one second prior to the epoch. |
+ int64_t milliseconds = 0; |
if (seconds == -1 && |
(exploded.year < 1969 || exploded.year > 1970)) { |
// If exploded.year is 1969 or 1970, take -1 as correct, with the |
@@ -312,13 +312,25 @@ bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) { |
milliseconds += (kMillisecondsPerSecond - 1); |
} |
} else { |
- milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond; |
+ base::CheckedNumeric<int64_t> checked_millis = seconds; |
+ checked_millis *= kMillisecondsPerSecond; |
+ checked_millis += exploded.millisecond; |
+ if (!checked_millis.IsValid()) { |
+ *time = base::Time(0); |
+ return false; |
+ } |
+ milliseconds = checked_millis.ValueOrDie(); |
} |
- // Adjust from Unix (1970) to Windows (1601) epoch. |
- base::Time converted_time = |
- Time((milliseconds * kMicrosecondsPerMillisecond) + |
- kWindowsEpochDeltaMicroseconds); |
+ // Adjust from Unix (1970) to Windows (1601) epoch avoiding overflows. |
+ base::CheckedNumeric<int64_t> checked_microseconds_win_epoch = milliseconds; |
+ checked_microseconds_win_epoch *= kMicrosecondsPerMillisecond; |
+ checked_microseconds_win_epoch += kWindowsEpochDeltaMicroseconds; |
+ if (!checked_microseconds_win_epoch.IsValid()) { |
+ *time = base::Time(0); |
+ return false; |
+ } |
+ base::Time converted_time(checked_microseconds_win_epoch.ValueOrDie()); |
// If |exploded.day_of_month| is set to 31 on a 28-30 day month, it will |
// return the first day of the next month. Thus round-trip the time and |