Commit 4cc4ebb0 authored by Ben Murdoch's avatar Ben Murdoch Committed by Android Git Automerger
Browse files

am 3919f93d: Cherry pick android: fix base::Time::FromLocalExploded() crash.

* commit '3919f93d':
  Cherry pick android: fix base::Time::FromLocalExploded() crash.
parents c1be817f 3919f93d
......@@ -211,9 +211,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
......@@ -234,14 +266,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 {
......
......@@ -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();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment