diff --git a/base/time/time.h b/base/time/time.h index 12e43d9e7a02c..286c0738ceb45 100644 --- a/base/time/time.h +++ b/base/time/time.h @@ -545,7 +545,7 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> { // Converts an exploded structure representing either the local time or UTC // into a Time class. Returns false on a failure when, for example, a day of - // month is set to 31 on a 28-30 day month. + // month is set to 31 on a 28-30 day month. Returns Time(0) on overflow. static bool FromUTCExploded(const Exploded& exploded, Time* time) WARN_UNUSED_RESULT { return FromExploded(false, exploded, time); diff --git a/base/time/time_mac.cc b/base/time/time_mac.cc index 5803acd35117c..c75423df9c222 100644 --- a/base/time/time_mac.cc +++ b/base/time/time_mac.cc @@ -190,9 +190,18 @@ bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) { exploded.millisecond); CFAbsoluteTime seconds = absolute_time + kCFAbsoluteTimeIntervalSince1970; - base::Time converted_time = - Time(static_cast<int64_t>(seconds * kMicrosecondsPerSecond) + - kWindowsEpochDeltaMicroseconds); + // CFAbsolutTime is typedef of double. Convert seconds to + // microseconds and then cast to int64. If + // it cannot be suited to int64, then fail to avoid overflows. + double microseconds = + (seconds * kMicrosecondsPerSecond) + kWindowsEpochDeltaMicroseconds; + if (microseconds > std::numeric_limits<int64_t>::max() || + microseconds < std::numeric_limits<int64_t>::min()) { + *time = Time(0); + return false; + } + + base::Time converted_time = Time(static_cast<int64_t>(microseconds)); // 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. diff --git a/base/time/time_posix.cc b/base/time/time_posix.cc index ac0e99f7eb61b..4caf3866c524f 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 diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc index 313eaea51f703..a42d701f25a22 100644 --- a/base/time/time_unittest.cc +++ b/base/time/time_unittest.cc @@ -54,6 +54,11 @@ TEST(TimeTestOutOfBounds, FromExplodedOutOfBoundsTime) { {{2016, 10, 0, 25, 7, 47, 234, 0}, false}, // Milliseconds are too large {{2016, 10, 0, 25, 6, 31, 23, 1643}, false}, + // Test overflow. Time is valid, but overflow case + // results in Time(0). + {{9840633, 1, 0, 1, 1, 1, 0, 0}, true}, + // Underflow will fail as well. + {{-9840633, 1, 0, 1, 1, 1, 0, 0}, true}, }; for (const auto& test : kDateTestData) { diff --git a/base/time/time_win.cc b/base/time/time_win.cc index 631eb3a292bbc..19144cb2792e3 100644 --- a/base/time/time_win.cc +++ b/base/time/time_win.cc @@ -110,6 +110,12 @@ uint64_t QPCNowRaw() { return perf_counter_now.QuadPart; } +bool SafeConvertToWord(int in, WORD* out) { + base::CheckedNumeric<WORD> result = in; + *out = result.ValueOrDefault(std::numeric_limits<WORD>::max()); + return result.IsValid(); +} + } // namespace // Time ----------------------------------------------------------------------- @@ -238,16 +244,20 @@ bool Time::IsHighResolutionTimerInUse() { // static bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) { // Create the system struct representing our exploded time. It will either be - // in local time or UTC. + // in local time or UTC.If casting from int to WORD results in overflow, + // fail and return Time(0). SYSTEMTIME st; - st.wYear = static_cast<WORD>(exploded.year); - st.wMonth = static_cast<WORD>(exploded.month); - st.wDayOfWeek = static_cast<WORD>(exploded.day_of_week); - st.wDay = static_cast<WORD>(exploded.day_of_month); - st.wHour = static_cast<WORD>(exploded.hour); - st.wMinute = static_cast<WORD>(exploded.minute); - st.wSecond = static_cast<WORD>(exploded.second); - st.wMilliseconds = static_cast<WORD>(exploded.millisecond); + if (!SafeConvertToWord(exploded.year, &st.wYear) || + !SafeConvertToWord(exploded.month, &st.wMonth) || + !SafeConvertToWord(exploded.day_of_week, &st.wDayOfWeek) || + !SafeConvertToWord(exploded.day_of_month, &st.wDay) || + !SafeConvertToWord(exploded.hour, &st.wHour) || + !SafeConvertToWord(exploded.minute, &st.wMinute) || + !SafeConvertToWord(exploded.second, &st.wSecond) || + !SafeConvertToWord(exploded.millisecond, &st.wMilliseconds)) { + *time = base::Time(0); + return false; + } FILETIME ft; bool success = true; diff --git a/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc b/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc index 6dc60c8235d45..a69344d5321e5 100644 --- a/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc @@ -29,6 +29,7 @@ base::Time::Exploded TestExplodedTime() { exploded.year = 2001; exploded.month = 12; exploded.day_of_month = 31; + exploded.day_of_week = 1; exploded.hour = 12; exploded.minute = 1; exploded.second = 0; diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc index 8c4a55c953111..aaf3afcd5de75 100644 --- a/media/ffmpeg/ffmpeg_common.cc +++ b/media/ffmpeg/ffmpeg_common.cc @@ -753,6 +753,9 @@ bool FFmpegUTCDateToTime(const char* date_utc, base::Time* out) { base::Time::Exploded exploded; exploded.millisecond = 0; + // This field cannot be uninitialized. Unless not modified, make it 0 here + // then. + exploded.day_of_week = 0; if (base::StringToInt(date_fields[0], &exploded.year) && base::StringToInt(date_fields[1], &exploded.month) && base::StringToInt(date_fields[2], &exploded.day_of_month) && diff --git a/media/formats/webm/webm_info_parser.cc b/media/formats/webm/webm_info_parser.cc index 6cce65b49eb71..1e13ef71189da 100644 --- a/media/formats/webm/webm_info_parser.cc +++ b/media/formats/webm/webm_info_parser.cc @@ -86,6 +86,7 @@ bool WebMInfoParser::OnBinary(int id, const uint8_t* data, int size) { exploded_epoch.year = 2001; exploded_epoch.month = 1; exploded_epoch.day_of_month = 1; + exploded_epoch.day_of_week = 1; exploded_epoch.hour = 0; exploded_epoch.minute = 0; exploded_epoch.second = 0; diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc index 24895905b07e2..c7216e19473dd 100644 --- a/media/test/pipeline_integration_test.cc +++ b/media/test/pipeline_integration_test.cc @@ -173,6 +173,7 @@ static base::Time kLiveTimelineOffset() { exploded_time.year = 2012; exploded_time.month = 11; exploded_time.day_of_month = 10; + exploded_time.day_of_week = 6; exploded_time.hour = 12; exploded_time.minute = 34; exploded_time.second = 56; diff --git a/net/http/http_util_unittest.cc b/net/http/http_util_unittest.cc index 5d443340e49a8..f2c2146215ecc 100644 --- a/net/http/http_util_unittest.cc +++ b/net/http/http_util_unittest.cc @@ -964,10 +964,10 @@ TEST(HttpUtilTest, ParseRanges) { } TEST(HttpUtilTest, ParseRetryAfterHeader) { - base::Time::Exploded now_exploded = { 2014, 11, -1, 5, 22, 39, 30, 0 }; + base::Time::Exploded now_exploded = {2014, 11, 4, 5, 22, 39, 30, 0}; base::Time now = base::Time::FromUTCExploded(now_exploded); - base::Time::Exploded later_exploded = { 2015, 1, -1, 1, 12, 34, 56, 0 }; + base::Time::Exploded later_exploded = {2015, 1, 5, 1, 12, 34, 56, 0}; base::Time later = base::Time::FromUTCExploded(later_exploded); const struct {