From cd9bc6c3a683b43f6a3f8674c94df768eed1d91d Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Fri, 28 Oct 2011 08:45:04 +0000 Subject: [PATCH] Fix error handling in Date.prototype.toISOString. This fixes Date.prototyoe.toISOString to throw a RangeError exception for invalid time values. It also includes a fix to removes the arbitrary (and completely bogus) range limit on the date value during construction of a Date object. Note that we still have bogus range limits on the year and month values. R=lrn@chromium.org BUG=v8:1792 TEST=mjsunit/date,test262/15.9.5.43-0-* Review URL: http://codereview.chromium.org/8392036 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9829 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/date.js | 10 +++++----- src/macros.py | 2 -- src/messages.js | 1 + src/runtime.cc | 23 +++++++++++------------ src/runtime.h | 2 +- test/mjsunit/date.js | 15 +++++++++++++-- test/test262/test262.status | 24 ------------------------ 7 files changed, 31 insertions(+), 46 deletions(-) diff --git a/src/date.js b/src/date.js index ccefce5763..d603671774 100644 --- a/src/date.js +++ b/src/date.js @@ -351,13 +351,12 @@ function MakeDay(year, month, date) { date = TO_INTEGER_MAP_MINUS_ZERO(date); if (year < kMinYear || year > kMaxYear || - month < kMinMonth || month > kMaxMonth || - date < kMinDate || date > kMaxDate) { + month < kMinMonth || month > kMaxMonth) { return $NaN; } - // Now we rely on year, month and date being SMIs. - return %DateMakeDay(year, month, date); + // Now we rely on year and month being SMIs. + return %DateMakeDay(year, month) + date - 1; } @@ -978,9 +977,10 @@ function PadInt(n, digits) { } +// ECMA 262 - 15.9.5.43 function DateToISOString() { var t = DATE_VALUE(this); - if (NUMBER_IS_NAN(t)) return kInvalidDate; + if (NUMBER_IS_NAN(t)) throw MakeRangeError("invalid_time_value", []); var year = this.getUTCFullYear(); var year_string; if (year >= 0 && year <= 9999) { diff --git a/src/macros.py b/src/macros.py index a42e83c602..bf7119feaa 100644 --- a/src/macros.py +++ b/src/macros.py @@ -82,8 +82,6 @@ const kMinYear = -1000000; const kMaxYear = 1000000; const kMinMonth = -10000000; const kMaxMonth = 10000000; -const kMinDate = -100000000; -const kMaxDate = 100000000; # Native cache ids. const STRING_TO_REGEXP_CACHE_ID = 0; diff --git a/src/messages.js b/src/messages.js index e4607abd2a..b370422d3d 100644 --- a/src/messages.js +++ b/src/messages.js @@ -198,6 +198,7 @@ function FormatMessage(message) { // RangeError "invalid_array_length", ["Invalid array length"], "stack_overflow", ["Maximum call stack size exceeded"], + "invalid_time_value", ["Invalid time value"], // SyntaxError "unable_to_parse", ["Parse error"], "invalid_regexp_flags", ["Invalid flags supplied to RegExp constructor '", "%0", "'"], diff --git a/src/runtime.cc b/src/runtime.cc index 9c23c2c967..43f84b41c7 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -7490,7 +7490,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) { } -static int MakeDay(int year, int month, int day) { +static int MakeDay(int year, int month) { static const int day_from_month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152, @@ -7527,23 +7527,22 @@ static int MakeDay(int year, int month, int day) { year1 / 400 - base_day; - if (year % 4 || (year % 100 == 0 && year % 400 != 0)) { - return day_from_year + day_from_month[month] + day - 1; + if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) { + return day_from_year + day_from_month[month]; } - return day_from_year + day_from_month_leap[month] + day - 1; + return day_from_year + day_from_month_leap[month]; } RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) { NoHandleAllocation ha; - ASSERT(args.length() == 3); + ASSERT(args.length() == 2); CONVERT_SMI_ARG_CHECKED(year, 0); CONVERT_SMI_ARG_CHECKED(month, 1); - CONVERT_SMI_ARG_CHECKED(date, 2); - return Smi::FromInt(MakeDay(year, month, date)); + return Smi::FromInt(MakeDay(year, month)); } @@ -7772,7 +7771,7 @@ static inline void DateYMDFromTimeAfter1970(int date, month = kMonthInYear[date]; day = kDayInYear[date]; - ASSERT(MakeDay(year, month, day) == save_date); + ASSERT(MakeDay(year, month) + day - 1 == save_date); } @@ -7786,7 +7785,7 @@ static inline void DateYMDFromTimeSlow(int date, year = 400 * (date / kDaysIn400Years) - kYearsOffset; date %= kDaysIn400Years; - ASSERT(MakeDay(year, 0, 1) + date == save_date); + ASSERT(MakeDay(year, 0) + date == save_date); date--; int yd1 = date / kDaysIn100Years; @@ -7809,8 +7808,8 @@ static inline void DateYMDFromTimeSlow(int date, ASSERT(is_leap || (date >= 0)); ASSERT((date < 365) || (is_leap && (date < 366))); ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0)))); - ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date)); - ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date)); + ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date)); + ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date)); if (is_leap) { day = kDayInYear[2*365 + 1 + date]; @@ -7820,7 +7819,7 @@ static inline void DateYMDFromTimeSlow(int date, month = kMonthInYear[date]; } - ASSERT(MakeDay(year, month, day) == save_date); + ASSERT(MakeDay(year, month) + day - 1 == save_date); } diff --git a/src/runtime.h b/src/runtime.h index 67fc6282a2..e6b63d2962 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -246,7 +246,7 @@ namespace internal { F(DateLocalTimezone, 1, 1) \ F(DateLocalTimeOffset, 0, 1) \ F(DateDaylightSavingsOffset, 1, 1) \ - F(DateMakeDay, 3, 1) \ + F(DateMakeDay, 2, 1) \ F(DateYMDFromTime, 2, 1) \ \ /* Numbers */ \ diff --git a/test/mjsunit/date.js b/test/mjsunit/date.js index a7f6cfa7d5..f74a13c692 100644 --- a/test/mjsunit/date.js +++ b/test/mjsunit/date.js @@ -157,7 +157,7 @@ testToLocaleTimeString(); // Test that -0 is treated correctly in MakeDay. var d = new Date(); assertDoesNotThrow("d.setDate(-0)"); -assertDoesNotThrow("new Date(-0, -0, -0, -0, -0, -0. -0)"); +assertDoesNotThrow("new Date(-0, -0, -0, -0, -0, -0, -0)"); assertDoesNotThrow("new Date(0x40000000, 0x40000000, 0x40000000," + "0x40000000, 0x40000000, 0x40000000, 0x40000000)") assertDoesNotThrow("new Date(-0x40000001, -0x40000001, -0x40000001," + @@ -178,7 +178,7 @@ assertTrue(isNaN(Date.UTC(-271821, 3, 19, 23, 59, 59, 999))); assertTrue(isNaN(Date.UTC(-271821, 3, 19))); -// Test creation of large date values. +// Test creation with large date values. d = new Date(1969, 12, 1, 99999999999); assertTrue(isNaN(d.getTime())); d = new Date(1969, 12, 1, -99999999999); @@ -188,6 +188,17 @@ assertTrue(isNaN(d.getTime())); d = new Date(1969, 12, 1, -Infinity); assertTrue(isNaN(d.getTime())); + +// Test creation with obscure date values. +var timezoneOffset = new Date().getTimezoneOffset(); +d = new Date(1970, 0, 1 + 100000001, -24, -timezoneOffset); +assertFalse(isNaN(d.getTime())); +assertEquals(8640000000000000, d.getTime()) +d = new Date(1970, 0, 1 - 100000001, 24, -timezoneOffset); +assertFalse(isNaN(d.getTime())); +assertEquals(-8640000000000000, d.getTime()) + + // Parsing ES5 ISO-8601 dates. // When TZ is omitted, it defaults to 'Z' meaning UTC. diff --git a/test/test262/test262.status b/test/test262/test262.status index bfd68fbaf2..7dcf01028b 100644 --- a/test/test262/test262.status +++ b/test/test262/test262.status @@ -131,12 +131,6 @@ S15.3_A3_T3: FAIL ##################### DELIBERATE INCOMPATIBILITIES ##################### -# 15.9.5.43-0-9 and 15.9.5.43-0-10. V8 doesn't throw RangeError -# from Date.prototype.toISOString when string is not a finite number. -# This is compatible with Firefox and Safari. -15.9.5.43-0-9: PASS || FAIL -15.9.5.43-0-10: PASS || FAIL - # We deliberately treat arguments to parseInt() with a leading zero as # octal numbers in order to not break the web. S15.1.2.2_A5.1_T1: FAIL_OK @@ -478,24 +472,6 @@ S15.4.4.3_A2_T1: FAIL_OK # Bug? Array.prototype.reduceRight - decreasing length of array does not delete # non-configurable properties 15.4.4.22-9-b-29: FAIL -# Bug? Date.prototype.toISOString - RangeError is thrown when value of date is -# Date(1970, 0, -99999999, 0, 0, 0, -1), the time zone is UTC(0) -15.9.5.43-0-8: FAIL -# Bug? Date.prototype.toISOString - RangeError is not thrown when value of date -# is Date(1970, 0, 100000001, 0, 0, 0, -1), the time zone is UTC(0) -15.9.5.43-0-11: FAIL -# Bug? Date.prototype.toISOString - RangeError is not thrown when value of date -# is Date(1970, 0, 100000001, 0, 0, 0, 0), the time zone is UTC(0) -15.9.5.43-0-12: FAIL -# Bug? Date.prototype.toISOString - RangeError is thrown when value of date is -# Date(1970, 0, 100000001, 0, 0, 0, 1), the time zone is UTC(0) -15.9.5.43-0-13: FAIL -# Bug? Date.prototype.toISOString - when value of year is -Infinity -# Date.prototype.toISOString throw the RangeError -15.9.5.43-0-14: FAIL -# Bug? Date.prototype.toISOString - value of year is Infinity -# Date.prototype.toISOString throw the RangeError -15.9.5.43-0-15: FAIL ############################ SKIPPED TESTS #############################