<https://webkit.org/b/131248>
Reviewed by Mark Hahnenberg.
Source/JavaScriptCore:
The current Date object code does not adequately check for the ES5
15.9.1.14 TimeClip limit. As a result, some calculations can underflow
/ overflow and produce unexpected results.
For example, we were getting an assertion failure in
WTF::equivalentYearForDST() due int underflows in this function, which
in turn were due to an int overflow in WTF::msToYear().
This patch adds the needed checks, and adds some assertions to ensure
that the used values are sane.
The changes have no noticeable impact on benchmark results.
* runtime/DateConstructor.cpp:
(JSC::callDate):
* runtime/JSDateMath.cpp:
(JSC::localTimeOffset):
(JSC::gregorianDateTimeToMS):
(JSC::msToGregorianDateTime):
(JSC::parseDateFromNullTerminatedCharacters):
(JSC::parseDate):
* runtime/JSDateMath.h:
- parseDateFromNullTerminatedCharacters() does not need to be public.
Made it a static function.
* runtime/VM.cpp:
(JSC::VM::resetDateCache):
- Changed cachedDateStringValue to use std::numeric_limits<double>::quiet_NaN()
to be consistent with other Date code.
Source/WTF:
* wtf/DateMath.cpp:
- Moved the definition of maxECMAScriptTime to the .h file so that we
can use it in other files as well.
(WTF::msToYear):
- Removed a stale comment for parseDateFromNullTerminatedCharacters().
* wtf/DateMath.h:
LayoutTests:
* js/regress-131248-expected.txt: Added.
* js/regress-131248.html: Added.
* js/script-tests/regress-131248.js: Added.
(testDateFromSetDateAdjustement):
(testDateFromSetTimeWithMilliseconds):
(testDateFromString):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@166876
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2014-04-04 Mark Lam <mark.lam@apple.com>
+
+ Date object needs to check for ES5 15.9.1.14 TimeClip limit.
+ <https://webkit.org/b/131248>
+
+ Reviewed by Mark Hahnenberg.
+
+ * js/regress-131248-expected.txt: Added.
+ * js/regress-131248.html: Added.
+ * js/script-tests/regress-131248.js: Added.
+ (testDateFromSetDateAdjustement):
+ (testDateFromSetTimeWithMilliseconds):
+ (testDateFromString):
+
2014-04-07 Sergio Villar Senin <svillar@igalia.com>
Unreviewed gardening for GTK.
--- /dev/null
+This test checks date values at the limits set by the ES5 15.9.1.14 TimeClip specification and ensures that we don't crash on any assertions.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+(new Date(1396547803766)).setDate(1396549003769) ==> NaN ms, Invalid Date
+(new Date(1396547803766)).setDate(100000000) ==> NaN ms, Invalid Date
+(new Date(1396547803766)).setDate(99983840) ==> NaN ms, Invalid Date
+(new Date(1396547803766)).setDate(99983839) ==> 8639999978203766 ms, Fri Sep 12 275760
+(new Date(1396547803766)).setDate(10000000) ==> 865396288603766 ms, Thu Apr 25 29393
+
+(new Date(0)).setTime(8640000000000001) ==> NaN ms, Invalid Date NaN ms
+(new Date(0)).setTime(8640000000000000) ==> 8640000000000000 ms, Sat, 13 Sep 275760 00:00:00 GMT 0 ms
+(new Date(0)).setTime(-8640000000000000) ==> -8640000000000000 ms, Tue, 20 Apr -271821 00:00:00 GMT 0 ms
+(new Date(0)).setTime(-8640000000000001) ==> NaN ms, Invalid Date NaN ms
+
+(new Date(13 Sep 275760 00:00:00 -0001) ==> NaN ms, Invalid Date NaN ms
+(new Date(13 Sep 275760 00:00:00 +0000) ==> 8640000000000000 ms, Sat, 13 Sep 275760 00:00:00 GMT 0 ms
+(new Date(13 Sep 275760 00:00:00 +0001) ==> 8639999996400000 ms, Fri, 12 Sep 275760 23:00:00 GMT 0 ms
+(new Date(20 Apr -271821 00:00:00 -0001) ==> -8639999996400000 ms, Tue, 20 Apr -271821 01:00:00 GMT 0 ms
+(new Date(20 Apr -271821 00:00:00 +0000) ==> -8640000000000000 ms, Tue, 20 Apr -271821 00:00:00 GMT 0 ms
+(new Date(20 Apr -271821 00:00:00 +0001) ==> NaN ms, Invalid Date NaN ms
+
+(new Date(19 Apr -271821 23:59:59) ==> NaN ms, Invalid Date NaN ms
+
+(new Date(275760-09-13T00:00:00.001) ==> NaN ms, Invalid Date NaN ms
+(new Date(275760-09-13T00:00:00.000) ==> 8640000000000000 ms, Sat, 13 Sep 275760 00:00:00 GMT 0 ms
+(new Date(-271821-04-20T00:00:00.0000) ==> -8640000000000000 ms, Tue, 20 Apr -271821 00:00:00 GMT 0 ms
+(new Date(-271821-04-19T23:59:59.999) ==> NaN ms, Invalid Date NaN ms
+
+(new Date(Sat, 13 Sep 275760 00:00:00 UTC-2) ==> NaN ms, Invalid Date NaN ms
+(new Date(Sat, 13 Sep 275760 00:00:00 UTC) ==> 8640000000000000 ms, Sat, 13 Sep 275760 00:00:00 GMT 0 ms
+(new Date(Sat, 13 Sep 275760 00:00:00 UTC+2) ==> 8639999992800000 ms, Fri, 12 Sep 275760 22:00:00 GMT 0 ms
+(new Date(Tue, 20 Apr -271821 00:00:00 UTC-2) ==> -8639999992800000 ms, Tue, 20 Apr -271821 02:00:00 GMT 0 ms
+(new Date(Tue, 20 Apr -271821 00:00:00 UTC) ==> -8640000000000000 ms, Tue, 20 Apr -271821 00:00:00 GMT 0 ms
+(new Date(Tue, 20 Apr -271821 00:00:00 UTC+2) ==> NaN ms, Invalid Date NaN ms
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/regress-131248.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+description(
+"This test checks date values at the limits set by the ES5 15.9.1.14 TimeClip specification and ensures that we don't crash on any assertions."
+);
+
+function testDateFromSetDateAdjustement(initialMs, adjustMs) {
+ var date = new Date(initialMs);
+ debug("(new Date(" + initialMs + ")).setDate(" + adjustMs + ") ==> " + date.setDate(adjustMs) + " ms, " + date.toDateString());
+}
+
+testDateFromSetDateAdjustement(1396547803766, 1396549003769);
+testDateFromSetDateAdjustement(1396547803766, 100000000);
+testDateFromSetDateAdjustement(1396547803766, 99983839+1);
+testDateFromSetDateAdjustement(1396547803766, 99983839);
+testDateFromSetDateAdjustement(1396547803766, 10000000);
+debug("");
+
+function testDateFromSetTimeWithMilliseconds(ms) {
+ var date = new Date(0);
+ debug("(new Date(0)).setTime(" + ms + ") ==> " + date.setTime(ms) + " ms, " + date.toUTCString() + " " + date.getUTCMilliseconds() + " ms");
+}
+
+testDateFromSetTimeWithMilliseconds(8640000000000001);
+testDateFromSetTimeWithMilliseconds(8640000000000000);
+testDateFromSetTimeWithMilliseconds(-8640000000000000);
+testDateFromSetTimeWithMilliseconds(-8640000000000001);
+debug("");
+
+function testDateFromString(str) {
+ var date = new Date(str);
+ debug("(new Date(" + str + ") ==> " + date.getTime() + " ms, " + date.toUTCString() + " " + date.getUTCMilliseconds() + " ms");
+}
+
+testDateFromString("13 Sep 275760 00:00:00 -0001");
+testDateFromString("13 Sep 275760 00:00:00 +0000");
+testDateFromString("13 Sep 275760 00:00:00 +0001");
+testDateFromString("20 Apr -271821 00:00:00 -0001");
+testDateFromString("20 Apr -271821 00:00:00 +0000");
+testDateFromString("20 Apr -271821 00:00:00 +0001");
+debug("");
+
+testDateFromString("19 Apr -271821 23:59:59");
+debug("");
+
+testDateFromString("275760-09-13T00:00:00.001");
+testDateFromString("275760-09-13T00:00:00.000");
+testDateFromString("-271821-04-20T00:00:00.0000");
+testDateFromString("-271821-04-19T23:59:59.999");
+debug("");
+
+testDateFromString("Sat, 13 Sep 275760 00:00:00 UTC-2");
+testDateFromString("Sat, 13 Sep 275760 00:00:00 UTC");
+testDateFromString("Sat, 13 Sep 275760 00:00:00 UTC+2");
+testDateFromString("Tue, 20 Apr -271821 00:00:00 UTC-2");
+testDateFromString("Tue, 20 Apr -271821 00:00:00 UTC");
+testDateFromString("Tue, 20 Apr -271821 00:00:00 UTC+2");
+debug("");
+
+2014-04-04 Mark Lam <mark.lam@apple.com>
+
+ Date object needs to check for ES5 15.9.1.14 TimeClip limit.
+ <https://webkit.org/b/131248>
+
+ Reviewed by Mark Hahnenberg.
+
+ The current Date object code does not adequately check for the ES5
+ 15.9.1.14 TimeClip limit. As a result, some calculations can underflow
+ / overflow and produce unexpected results.
+
+ For example, we were getting an assertion failure in
+ WTF::equivalentYearForDST() due int underflows in this function, which
+ in turn were due to an int overflow in WTF::msToYear().
+
+ This patch adds the needed checks, and adds some assertions to ensure
+ that the used values are sane.
+
+ The changes have no noticeable impact on benchmark results.
+
+ * runtime/DateConstructor.cpp:
+ (JSC::callDate):
+ * runtime/JSDateMath.cpp:
+ (JSC::localTimeOffset):
+ (JSC::gregorianDateTimeToMS):
+ (JSC::msToGregorianDateTime):
+ (JSC::parseDateFromNullTerminatedCharacters):
+ (JSC::parseDate):
+ * runtime/JSDateMath.h:
+ - parseDateFromNullTerminatedCharacters() does not need to be public.
+ Made it a static function.
+ * runtime/VM.cpp:
+ (JSC::VM::resetDateCache):
+ - Changed cachedDateStringValue to use std::numeric_limits<double>::quiet_NaN()
+ to be consistent with other Date code.
+
2014-04-06 Csaba Osztrogonác <ossy@webkit.org>
Unreviewed speculative 32-bit buildfix after r166837.
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2008, 2011, 2014 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
{
VM& vm = exec->vm();
GregorianDateTime ts;
- msToGregorianDateTime(vm, currentTimeMS(), false, ts);
+
+ double currentTime = timeClip(currentTimeMS());
+ if (std::isnan(currentTime))
+ return JSValue::encode(jsNaN());
+
+ msToGregorianDateTime(vm, currentTime, false, ts);
return JSValue::encode(jsNontrivialString(&vm, formatDateTime(ts, DateTimeFormatDateAndTime, false)));
}
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2006, 2007, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2007, 2012, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
* Copyright (C) 2007-2009 Torch Mobile, Inc.
* Copyright (C) 2010 &yet, LLC. (nate@andyet.net)
double start = cache.start;
double end = cache.end;
+ ASSERT(fabs(ms) <= WTF::maxECMAScriptTime);
if (start <= ms) {
// If the time fits in the cached interval, return the cached offset.
if (ms <= end) return cache.offset;
// Compute a possible new interval end.
double newEnd = end + cache.increment;
- if (ms <= newEnd) {
+ if (ms <= newEnd && newEnd <= WTF::maxECMAScriptTime) {
LocalTimeOffset endOffset = calculateLocalTimeOffset(newEnd);
if (cache.offset == endOffset) {
// If the offset at the end of the new interval still matches
double ms = timeToMS(t.hour(), t.minute(), t.second(), milliSeconds);
double result = (day * WTF::msPerDay) + ms;
+ if (fabs(result) > WTF::maxECMAScriptTime)
+ return std::numeric_limits<double>::quiet_NaN();
+
if (!inputIsUTC)
result -= localTimeOffset(vm, result).offset;
- return result;
+ return timeClip(result);
}
// input is UTC
void msToGregorianDateTime(VM& vm, double ms, bool outputIsUTC, GregorianDateTime& tm)
{
+ ASSERT(fabs(ms) <= WTF::maxECMAScriptTime);
LocalTimeOffset localTime;
if (!outputIsUTC) {
localTime = localTimeOffset(vm, ms);
tm.setUtcOffset(localTime.offset / WTF::msPerSecond);
}
-double parseDateFromNullTerminatedCharacters(VM& vm, const char* dateString)
+static double parseDateFromNullTerminatedCharacters(VM& vm, const char* dateString)
{
bool haveTZ;
int offset;
double ms = WTF::parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset);
- if (std::isnan(ms))
- return QNaN;
+ if (std::isnan(ms) || fabs(ms) > WTF::maxECMAScriptTime)
+ return std::numeric_limits<double>::quiet_NaN();
// fall back to local timezone
if (!haveTZ)
double value = parseES5DateFromNullTerminatedCharacters(date.utf8().data());
if (std::isnan(value))
value = parseDateFromNullTerminatedCharacters(vm, date.utf8().data());
+ value = timeClip(value);
vm.cachedDateString = date;
vm.cachedDateStringValue = value;
return value;
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2007, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
* Copyright (C) 2010 Research In Motion Limited. All rights reserved.
*
void msToGregorianDateTime(VM&, double, bool outputIsUTC, GregorianDateTime&);
double gregorianDateTimeToMS(VM&, const GregorianDateTime&, double, bool inputIsUTC);
double getUTCOffset(VM&);
-double parseDateFromNullTerminatedCharacters(VM&, const char* dateString);
double parseDate(VM&, const WTF::String&);
} // namespace JSC
{
localTimeOffsetCache.reset();
cachedDateString = String();
- cachedDateStringValue = QNaN;
+ cachedDateStringValue = std::numeric_limits<double>::quiet_NaN();
dateInstanceCache.reset();
}
+2014-04-04 Mark Lam <mark.lam@apple.com>
+
+ Date object needs to check for ES5 15.9.1.14 TimeClip limit.
+ <https://webkit.org/b/131248>
+
+ Reviewed by Mark Hahnenberg.
+
+ * wtf/DateMath.cpp:
+ - Moved the definition of maxECMAScriptTime to the .h file so that we
+ can use it in other files as well.
+ (WTF::msToYear):
+ - Removed a stale comment for parseDateFromNullTerminatedCharacters().
+ * wtf/DateMath.h:
+
2014-04-04 Mark Hahnenberg <mhahnenberg@apple.com>
Enhanced GC logging
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2007, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
* Copyright (C) 2007-2009 Torch Mobile, Inc.
* Copyright (C) 2010 &yet, LLC. (nate@andyet.net)
/* Constants */
static const double maxUnixTime = 2145859200.0; // 12/31/2037
-// ECMAScript asks not to support for a date of which total
-// millisecond value is larger than the following value.
-// See 15.9.1.14 of ECMA-262 5th edition.
-static const double maxECMAScriptTime = 8.64E15;
// Day of year for the first day of each month, where index 0 is January, and day 0 is January 1.
// First for non-leap years, then for leap years.
int msToYear(double ms)
{
+ ASSERT(fabs(ms) <= maxECMAScriptTime);
int approxYear = static_cast<int>(floor(ms / (msPerDay * 365.2425)) + 1970);
double msFromApproxYearTo1970 = msPerDay * daysFrom1970ToYear(approxYear);
if (msFromApproxYearTo1970 > ms)
}
/*
- * Find an equivalent year for the one given, where equivalence is deterined by
+ * Find an equivalent year for the one given, where equivalence is determined by
* the two years having the same leapness and the first day of the year, falling
* on the same day of the week.
*
return dateSeconds * msPerSecond;
}
-// Odd case where 'exec' is allowed to be 0, to accomodate a caller in WebCore.
double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveTZ, int& offset)
{
haveTZ = false;
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2007, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
* Copyright (C) 2010 Research In Motion Limited. All rights reserved.
*
namespace WTF {
+// ECMAScript asks not to support for a date of which total
+// millisecond value is larger than the following value.
+// See 15.9.1.14 of ECMA-262 5th edition.
+static const double maxECMAScriptTime = 8.64E15;
+
struct LocalTimeOffset {
LocalTimeOffset()
: isDST(false)