summaryrefslogtreecommitdiffstats
path: root/base/time
diff options
context:
space:
mode:
authordigit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-19 15:38:50 +0000
committerdigit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-19 15:38:50 +0000
commit2a278516943eee02e0206506a4b907fc0b55f27b (patch)
treebf80d179b0b66b02de34b884bf55634cb427b6a1 /base/time
parentf5385e64e92cbd7f4afa670a4bb3abff3647ddde (diff)
downloadchromium_src-2a278516943eee02e0206506a4b907fc0b55f27b.zip
chromium_src-2a278516943eee02e0206506a4b907fc0b55f27b.tar.gz
chromium_src-2a278516943eee02e0206506a4b907fc0b55f27b.tar.bz2
android: fix base::Time::FromLocalExploded() crash.
This patch does the following: - Provide a work-around for an Android platform bug that happens on older Android releases (e.g. 4.1.2), but fixed on later ones (e.g. 4.3), where mktime() / mktime64() would return -1 even when passed proper time values. - Improve the code to properly deal with the fact that SysTime is actually int64 on Android, unlike other platforms, allowing us to remove the CHECK() that was triggered by the platform bug. - Add a new unit test to verify that the new code doesn't crash on Android 4.1.2 anymore, and returns the correct values. BUG=287821 R=jar@chromium.org,mark@chromium.org,brettw@chromium.org Review URL: https://codereview.chromium.org/27472003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@229567 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/time')
-rw-r--r--base/time/time_posix.cc51
-rw-r--r--base/time/time_unittest.cc24
2 files changed, 68 insertions, 7 deletions
diff --git a/base/time/time_posix.cc b/base/time/time_posix.cc
index 5e06ce9..c1edb7a 100644
--- a/base/time/time_posix.cc
+++ b/base/time/time_posix.cc
@@ -214,9 +214,41 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore
#endif
- SysTime seconds = SysTimeFromTimeStruct(&timestruct, is_local);
int64 milliseconds;
+ SysTime seconds;
+
+ // Certain exploded dates do not really exist due to daylight saving times,
+ // and this causes mktime() to return implementation-defined values when
+ // tm_isdst is set to -1. On Android, the function will return -1, while the
+ // C libraries of other platforms typically return a liberally-chosen value.
+ // Handling this requires the special code below.
+
+ // SysTimeFromTimeStruct() modifies the input structure, save current value.
+ struct tm timestruct0 = timestruct;
+
+ seconds = SysTimeFromTimeStruct(&timestruct, is_local);
+ if (seconds == -1) {
+ // Get the time values with tm_isdst == 0 and 1, then select the closest one
+ // to UTC 00:00:00 that isn't -1.
+ timestruct = timestruct0;
+ timestruct.tm_isdst = 0;
+ int64 seconds_isdst0 = SysTimeFromTimeStruct(&timestruct, is_local);
+
+ timestruct = timestruct0;
+ timestruct.tm_isdst = 1;
+ int64 seconds_isdst1 = SysTimeFromTimeStruct(&timestruct, is_local);
+
+ // seconds_isdst0 or seconds_isdst1 can be -1 for some timezones.
+ // E.g. "CLST" (Chile Summer Time) returns -1 for 'tm_isdt == 1'.
+ if (seconds_isdst0 < 0)
+ seconds = seconds_isdst1;
+ else if (seconds_isdst1 < 0)
+ seconds = seconds_isdst0;
+ else
+ seconds = std::min(seconds_isdst0, seconds_isdst1);
+ }
+
// Handle overflow. Clamping the range to what mktime and timegm might
// 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
@@ -237,14 +269,19 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
// When representing the most distant time in the future, add in an extra
// 999ms to avoid the time being less than any other possible value that
// this function can return.
+
+ // On Android, SysTime is int64, special care must be taken to avoid
+ // overflows.
+ const int64 min_seconds = (sizeof(SysTime) < sizeof(int64))
+ ? std::numeric_limits<SysTime>::min()
+ : std::numeric_limits<int32_t>::min();
+ const int64 max_seconds = (sizeof(SysTime) < sizeof(int64))
+ ? std::numeric_limits<SysTime>::max()
+ : std::numeric_limits<int32_t>::max();
if (exploded.year < 1969) {
- CHECK(sizeof(SysTime) < sizeof(int64)) << "integer overflow";
- milliseconds = std::numeric_limits<SysTime>::min();
- milliseconds *= kMillisecondsPerSecond;
+ milliseconds = min_seconds * kMillisecondsPerSecond;
} else {
- CHECK(sizeof(SysTime) < sizeof(int64)) << "integer overflow";
- milliseconds = std::numeric_limits<SysTime>::max();
- milliseconds *= kMillisecondsPerSecond;
+ milliseconds = max_seconds * kMillisecondsPerSecond;
milliseconds += (kMillisecondsPerSecond - 1);
}
} else {
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
index 7f3fde0..81a3358 100644
--- a/base/time/time_unittest.cc
+++ b/base/time/time_unittest.cc
@@ -7,6 +7,8 @@
#include <time.h>
#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -541,6 +543,28 @@ TEST_F(TimeTest, TimeTOverflow) {
}
#endif
+#if defined(OS_ANDROID)
+TEST_F(TimeTest, FromLocalExplodedCrashOnAndroid) {
+ // This crashed inside Time:: FromLocalExploded() on Android 4.1.2.
+ // See http://crbug.com/287821
+ Time::Exploded midnight = {2013, // year
+ 10, // month
+ 0, // day_of_week
+ 13, // day_of_month
+ 0, // hour
+ 0, // minute
+ 0, // second
+ };
+ // The string passed to putenv() must be a char* and the documentation states
+ // that it 'becomes part of the environment', so use a static buffer.
+ static char buffer[] = "TZ=America/Santiago";
+ putenv(buffer);
+ tzset();
+ Time t = Time::FromLocalExploded(midnight);
+ EXPECT_EQ(1381633200, t.ToTimeT());
+}
+#endif // OS_ANDROID
+
TEST(TimeTicks, Deltas) {
for (int index = 0; index < 50; index++) {
TimeTicks ticks_start = TimeTicks::Now();