summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormkwst@chromium.org <mkwst@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-08 17:50:07 +0000
committermkwst@chromium.org <mkwst@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-08 17:50:07 +0000
commita9e5f04481565af0a3c8dbe770b14899f24b68f7 (patch)
tree4565198c5cdff1435acd19f5efc903eb306ee061
parent4a6d53c71fb914da3dd9e15cdc72b385b91701ec (diff)
downloadchromium_src-a9e5f04481565af0a3c8dbe770b14899f24b68f7.zip
chromium_src-a9e5f04481565af0a3c8dbe770b14899f24b68f7.tar.gz
chromium_src-a9e5f04481565af0a3c8dbe770b14899f24b68f7.tar.bz2
Fixing Time::Max()'s behavior with Time::ToTimeT() and friends.
It looks like the math that's done to convert epoch times between platforms is giving incorrect results when confronted with a "max" time. This CL adjusts the various conversion methods to persist maxness in the same way they currently persist zeroness. BUG=146328 Review URL: https://chromiumcodereview.appspot.com/10916089 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155591 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/time.cc29
-rw-r--r--base/time.h7
-rw-r--r--base/time_mac.cc4
-rw-r--r--base/time_posix.cc15
-rw-r--r--base/time_unittest.cc62
-rw-r--r--base/time_win.cc13
6 files changed, 124 insertions, 6 deletions
diff --git a/base/time.cc b/base/time.cc
index 7055311..f2f3168 100644
--- a/base/time.cc
+++ b/base/time.cc
@@ -74,12 +74,23 @@ Time Time::Max() {
Time Time::FromTimeT(time_t tt) {
if (tt == 0)
return Time(); // Preserve 0 so we can tell it doesn't exist.
+ if (tt == std::numeric_limits<time_t>::max())
+ return Max();
return Time((tt * kMicrosecondsPerSecond) + kTimeTToMicrosecondsOffset);
}
time_t Time::ToTimeT() const {
- if (us_ == 0)
+ if (is_null())
return 0; // Preserve 0 so we can tell it doesn't exist.
+ if (is_max()) {
+ // Preserve max without offset to prevent overflow.
+ return std::numeric_limits<time_t>::max();
+ }
+ if (std::numeric_limits<int64>::max() - kTimeTToMicrosecondsOffset <= us_) {
+ DLOG(WARNING) << "Overflow when converting base::Time with internal " <<
+ "value " << us_ << " to time_t.";
+ return std::numeric_limits<time_t>::max();
+ }
return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond;
}
@@ -87,14 +98,20 @@ time_t Time::ToTimeT() const {
Time Time::FromDoubleT(double dt) {
if (dt == 0 || isnan(dt))
return Time(); // Preserve 0 so we can tell it doesn't exist.
+ if (dt == std::numeric_limits<double>::max())
+ return Max();
return Time(static_cast<int64>((dt *
static_cast<double>(kMicrosecondsPerSecond)) +
kTimeTToMicrosecondsOffset));
}
double Time::ToDoubleT() const {
- if (us_ == 0)
+ if (is_null())
return 0; // Preserve 0 so we can tell it doesn't exist.
+ if (is_max()) {
+ // Preserve max without offset to prevent overflow.
+ return std::numeric_limits<double>::max();
+ }
return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
static_cast<double>(kMicrosecondsPerSecond));
}
@@ -103,15 +120,21 @@ double Time::ToDoubleT() const {
Time Time::FromJsTime(double ms_since_epoch) {
// The epoch is a valid time, so this constructor doesn't interpret
// 0 as the null time.
+ if (ms_since_epoch == std::numeric_limits<double>::max())
+ return Max();
return Time(static_cast<int64>(ms_since_epoch * kMicrosecondsPerMillisecond) +
kTimeTToMicrosecondsOffset);
}
double Time::ToJsTime() const {
- if (us_ == 0) {
+ if (is_null()) {
// Preserve 0 so the invalid result doesn't depend on the platform.
return 0;
}
+ if (is_max()) {
+ // Preserve max without offset to prevent overflow.
+ return std::numeric_limits<double>::max();
+ }
return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
kMicrosecondsPerMillisecond);
}
diff --git a/base/time.h b/base/time.h
index 4d9bf35..ceed500 100644
--- a/base/time.h
+++ b/base/time.h
@@ -45,6 +45,8 @@
#include <windows.h>
#endif
+#include <limits>
+
namespace base {
class Time;
@@ -246,6 +248,11 @@ class BASE_EXPORT Time {
return us_ == 0;
}
+ // Returns true if the time object is the maximum time.
+ bool is_max() const {
+ return us_ == std::numeric_limits<int64>::max();
+ }
+
// Returns the time for epoch in Unix-like system (Jan 1, 1970).
static Time UnixEpoch();
diff --git a/base/time_mac.cc b/base/time_mac.cc
index 98641bb..ca10bc8 100644
--- a/base/time_mac.cc
+++ b/base/time_mac.cc
@@ -54,6 +54,8 @@ Time Time::Now() {
Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
if (t == 0)
return Time(); // Consider 0 as a null Time.
+ if (t == std::numeric_limits<CFAbsoluteTime>::max())
+ return Max();
return Time(static_cast<int64>(
(t + kCFAbsoluteTimeIntervalSince1970) * kMicrosecondsPerSecond) +
kWindowsEpochDeltaMicroseconds);
@@ -62,6 +64,8 @@ Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
CFAbsoluteTime Time::ToCFAbsoluteTime() const {
if (is_null())
return 0; // Consider 0 as a null Time.
+ if (is_max())
+ return std::numeric_limits<CFAbsoluteTime>::max();
return (static_cast<CFAbsoluteTime>(us_ - kWindowsEpochDeltaMicroseconds) /
kMicrosecondsPerSecond) - kCFAbsoluteTimeIntervalSince1970;
}
diff --git a/base/time_posix.cc b/base/time_posix.cc
index c74cae5..c79781c 100644
--- a/base/time_posix.cc
+++ b/base/time_posix.cc
@@ -266,6 +266,11 @@ TimeTicks TimeTicks::NowFromSystemTraceTime() {
Time Time::FromTimeVal(struct timeval t) {
DCHECK_LT(t.tv_usec, static_cast<int>(Time::kMicrosecondsPerSecond));
DCHECK_GE(t.tv_usec, 0);
+ if (t.tv_usec == 0 && t.tv_sec == 0)
+ return Time();
+ if (t.tv_usec == static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1 &&
+ t.tv_sec == std::numeric_limits<time_t>::max())
+ return Max();
return Time(
(static_cast<int64>(t.tv_sec) * Time::kMicrosecondsPerSecond) +
t.tv_usec +
@@ -274,6 +279,16 @@ Time Time::FromTimeVal(struct timeval t) {
struct timeval Time::ToTimeVal() const {
struct timeval result;
+ if (is_null()) {
+ result.tv_sec = 0;
+ result.tv_usec = 0;
+ return result;
+ }
+ if (is_max()) {
+ result.tv_sec = std::numeric_limits<time_t>::max();
+ result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
+ return result;
+ }
int64 us = us_ - kTimeTToMicrosecondsOffset;
result.tv_sec = us / Time::kMicrosecondsPerSecond;
result.tv_usec = us % Time::kMicrosecondsPerSecond;
diff --git a/base/time_unittest.cc b/base/time_unittest.cc
index 5421ed1..dd6d26b 100644
--- a/base/time_unittest.cc
+++ b/base/time_unittest.cc
@@ -480,11 +480,67 @@ TEST_F(TimeTest, ExplodeBeforeUnixEpoch) {
}
TEST_F(TimeTest, Max) {
- EXPECT_EQ(base::Time::Max(), base::Time::Max());
- EXPECT_GT(base::Time::Max(), base::Time::Now());
- EXPECT_GT(base::Time::Max(), base::Time());
+ Time max = Time::Max();
+ EXPECT_TRUE(max.is_max());
+ EXPECT_EQ(max, Time::Max());
+ EXPECT_GT(max, Time::Now());
+ EXPECT_GT(max, Time());
}
+TEST_F(TimeTest, MaxConversions) {
+ Time t = Time::Max();
+ EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue());
+
+ t = Time::FromDoubleT(std::numeric_limits<double>::max());
+ EXPECT_TRUE(t.is_max());
+ EXPECT_EQ(std::numeric_limits<double>::max(), t.ToDoubleT());
+
+ t = Time::FromJsTime(std::numeric_limits<double>::max());
+ EXPECT_TRUE(t.is_max());
+ EXPECT_EQ(std::numeric_limits<double>::max(), t.ToJsTime());
+
+ t = Time::FromTimeT(std::numeric_limits<time_t>::max());
+ EXPECT_TRUE(t.is_max());
+ EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT());
+
+#if defined(OS_POSIX)
+ struct timeval tval;
+ tval.tv_sec = std::numeric_limits<time_t>::max();
+ tval.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
+ t = Time::FromTimeVal(tval);
+ EXPECT_TRUE(t.is_max());
+ tval = t.ToTimeVal();
+ EXPECT_EQ(std::numeric_limits<time_t>::max(), tval.tv_sec);
+ EXPECT_EQ(static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1,
+ tval.tv_usec);
+#endif
+
+#if defined(OS_MACOSX)
+ t = Time::FromCFAbsoluteTime(std::numeric_limits<CFAbsoluteTime>::max());
+ EXPECT_TRUE(t.is_max());
+ EXPECT_EQ(std::numeric_limits<CFAbsoluteTime>::max(), t.ToCFAbsoluteTime());
+#endif
+
+#if defined(OS_WIN)
+ FILETIME ftime;
+ ftime.dwHighDateTime = std::numeric_limits<DWORD>::max();
+ ftime.dwLowDateTime = std::numeric_limits<DWORD>::max();
+ t = Time::FromFileTime(ftime);
+ EXPECT_TRUE(t.is_max());
+ ftime = t.ToFileTime();
+ EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwHighDateTime);
+ EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwLowDateTime);
+#endif
+}
+
+#if defined(OS_MACOSX)
+TEST_F(TimeTest, TimeTOverflow) {
+ Time t = Time::FromInternalValue(std::numeric_limits<int64>::max() - 1);
+ EXPECT_FALSE(t.is_max());
+ EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT());
+}
+#endif
+
TEST(TimeTicks, Deltas) {
for (int index = 0; index < 50; index++) {
TimeTicks ticks_start = TimeTicks::Now();
diff --git a/base/time_win.cc b/base/time_win.cc
index 191b7a7..6d8e432 100644
--- a/base/time_win.cc
+++ b/base/time_win.cc
@@ -141,10 +141,23 @@ Time Time::NowFromSystemTime() {
// static
Time Time::FromFileTime(FILETIME ft) {
+ if (bit_cast<int64, FILETIME>(ft) == 0)
+ return Time();
+ if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() &&
+ ft.dwLowDateTime == std::numeric_limits<DWORD>::max())
+ return Max();
return Time(FileTimeToMicroseconds(ft));
}
FILETIME Time::ToFileTime() const {
+ if (is_null())
+ return bit_cast<FILETIME, int64>(0);
+ if (is_max()) {
+ FILETIME result;
+ result.dwHighDateTime = std::numeric_limits<DWORD>::max();
+ result.dwLowDateTime = std::numeric_limits<DWORD>::max();
+ return result;
+ }
FILETIME utc_ft;
MicrosecondsToFileTime(us_, &utc_ft);
return utc_ft;