Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(366)

Side by Side Diff: base/time/time_posix.cc

Issue 32883002: Merge 229567 "android: fix base::Time::FromLocalExploded() crash." (Closed) Base URL: svn://svn.chromium.org/chrome/branches/1599_82/src/
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | base/time/time_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/time/time.h" 5 #include "base/time/time.h"
6 6
7 #include <sys/time.h> 7 #include <sys/time.h>
8 #include <time.h> 8 #include <time.h>
9 #if defined(OS_ANDROID) 9 #if defined(OS_ANDROID)
10 #include <time64.h> 10 #include <time64.h>
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 timestruct.tm_mon = exploded.month - 1; 204 timestruct.tm_mon = exploded.month - 1;
205 timestruct.tm_year = exploded.year - 1900; 205 timestruct.tm_year = exploded.year - 1900;
206 timestruct.tm_wday = exploded.day_of_week; // mktime/timegm ignore this 206 timestruct.tm_wday = exploded.day_of_week; // mktime/timegm ignore this
207 timestruct.tm_yday = 0; // mktime/timegm ignore this 207 timestruct.tm_yday = 0; // mktime/timegm ignore this
208 timestruct.tm_isdst = -1; // attempt to figure it out 208 timestruct.tm_isdst = -1; // attempt to figure it out
209 #if !defined(OS_NACL) && !defined(OS_SOLARIS) 209 #if !defined(OS_NACL) && !defined(OS_SOLARIS)
210 timestruct.tm_gmtoff = 0; // not a POSIX field, so mktime/timegm ignore 210 timestruct.tm_gmtoff = 0; // not a POSIX field, so mktime/timegm ignore
211 timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore 211 timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore
212 #endif 212 #endif
213 213
214 SysTime seconds = SysTimeFromTimeStruct(&timestruct, is_local);
215 214
216 int64 milliseconds; 215 int64 milliseconds;
216 SysTime seconds;
217
218 // Certain exploded dates do not really exist due to daylight saving times,
219 // and this causes mktime() to return implementation-defined values when
220 // tm_isdst is set to -1. On Android, the function will return -1, while the
221 // C libraries of other platforms typically return a liberally-chosen value.
222 // Handling this requires the special code below.
223
224 // SysTimeFromTimeStruct() modifies the input structure, save current value.
225 struct tm timestruct0 = timestruct;
226
227 seconds = SysTimeFromTimeStruct(&timestruct, is_local);
228 if (seconds == -1) {
229 // Get the time values with tm_isdst == 0 and 1, then select the closest one
230 // to UTC 00:00:00 that isn't -1.
231 timestruct = timestruct0;
232 timestruct.tm_isdst = 0;
233 int64 seconds_isdst0 = SysTimeFromTimeStruct(&timestruct, is_local);
234
235 timestruct = timestruct0;
236 timestruct.tm_isdst = 1;
237 int64 seconds_isdst1 = SysTimeFromTimeStruct(&timestruct, is_local);
238
239 // seconds_isdst0 or seconds_isdst1 can be -1 for some timezones.
240 // E.g. "CLST" (Chile Summer Time) returns -1 for 'tm_isdt == 1'.
241 if (seconds_isdst0 < 0)
242 seconds = seconds_isdst1;
243 else if (seconds_isdst1 < 0)
244 seconds = seconds_isdst0;
245 else
246 seconds = std::min(seconds_isdst0, seconds_isdst1);
247 }
248
217 // Handle overflow. Clamping the range to what mktime and timegm might 249 // Handle overflow. Clamping the range to what mktime and timegm might
218 // return is the best that can be done here. It's not ideal, but it's better 250 // return is the best that can be done here. It's not ideal, but it's better
219 // than failing here or ignoring the overflow case and treating each time 251 // than failing here or ignoring the overflow case and treating each time
220 // overflow as one second prior to the epoch. 252 // overflow as one second prior to the epoch.
221 if (seconds == -1 && 253 if (seconds == -1 &&
222 (exploded.year < 1969 || exploded.year > 1970)) { 254 (exploded.year < 1969 || exploded.year > 1970)) {
223 // If exploded.year is 1969 or 1970, take -1 as correct, with the 255 // If exploded.year is 1969 or 1970, take -1 as correct, with the
224 // time indicating 1 second prior to the epoch. (1970 is allowed to handle 256 // time indicating 1 second prior to the epoch. (1970 is allowed to handle
225 // time zone and DST offsets.) Otherwise, return the most future or past 257 // time zone and DST offsets.) Otherwise, return the most future or past
226 // time representable. Assumes the time_t epoch is 1970-01-01 00:00:00 UTC. 258 // time representable. Assumes the time_t epoch is 1970-01-01 00:00:00 UTC.
227 // 259 //
228 // The minimum and maximum representible times that mktime and timegm could 260 // The minimum and maximum representible times that mktime and timegm could
229 // return are used here instead of values outside that range to allow for 261 // return are used here instead of values outside that range to allow for
230 // proper round-tripping between exploded and counter-type time 262 // proper round-tripping between exploded and counter-type time
231 // representations in the presence of possible truncation to time_t by 263 // representations in the presence of possible truncation to time_t by
232 // division and use with other functions that accept time_t. 264 // division and use with other functions that accept time_t.
233 // 265 //
234 // When representing the most distant time in the future, add in an extra 266 // When representing the most distant time in the future, add in an extra
235 // 999ms to avoid the time being less than any other possible value that 267 // 999ms to avoid the time being less than any other possible value that
236 // this function can return. 268 // this function can return.
269
270 // On Android, SysTime is int64, special care must be taken to avoid
271 // overflows.
272 const int64 min_seconds = (sizeof(SysTime) < sizeof(int64))
273 ? std::numeric_limits<SysTime>::min()
274 : std::numeric_limits<int32_t>::min();
275 const int64 max_seconds = (sizeof(SysTime) < sizeof(int64))
276 ? std::numeric_limits<SysTime>::max()
277 : std::numeric_limits<int32_t>::max();
237 if (exploded.year < 1969) { 278 if (exploded.year < 1969) {
238 CHECK(sizeof(SysTime) < sizeof(int64)) << "integer overflow"; 279 milliseconds = min_seconds * kMillisecondsPerSecond;
239 milliseconds = std::numeric_limits<SysTime>::min();
240 milliseconds *= kMillisecondsPerSecond;
241 } else { 280 } else {
242 CHECK(sizeof(SysTime) < sizeof(int64)) << "integer overflow"; 281 milliseconds = max_seconds * kMillisecondsPerSecond;
243 milliseconds = std::numeric_limits<SysTime>::max();
244 milliseconds *= kMillisecondsPerSecond;
245 milliseconds += (kMillisecondsPerSecond - 1); 282 milliseconds += (kMillisecondsPerSecond - 1);
246 } 283 }
247 } else { 284 } else {
248 milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond; 285 milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond;
249 } 286 }
250 287
251 // Adjust from Unix (1970) to Windows (1601) epoch. 288 // Adjust from Unix (1970) to Windows (1601) epoch.
252 return Time((milliseconds * kMicrosecondsPerMillisecond) + 289 return Time((milliseconds * kMicrosecondsPerMillisecond) +
253 kWindowsEpochDeltaMicroseconds); 290 kWindowsEpochDeltaMicroseconds);
254 } 291 }
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1; 372 result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
336 return result; 373 return result;
337 } 374 }
338 int64 us = us_ - kTimeTToMicrosecondsOffset; 375 int64 us = us_ - kTimeTToMicrosecondsOffset;
339 result.tv_sec = us / Time::kMicrosecondsPerSecond; 376 result.tv_sec = us / Time::kMicrosecondsPerSecond;
340 result.tv_usec = us % Time::kMicrosecondsPerSecond; 377 result.tv_usec = us % Time::kMicrosecondsPerSecond;
341 return result; 378 return result;
342 } 379 }
343 380
344 } // namespace base 381 } // namespace base
OLDNEW
« no previous file with comments | « no previous file | base/time/time_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698