From fc6155cf2c805f603afa4c749d8db872641909e8 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Tue, 26 Nov 2024 11:05:57 -0500 Subject: [PATCH] LibJS: Differentiate between failed ISO8601 parsing and invalid values If we were able to parse an ISO8601 Date string, but the parse results in an invalid date (e.g. out of the min/max range), we should abort parsing immediately. --- Libraries/LibJS/Runtime/DateConstructor.cpp | 12 +++++------- Libraries/LibJS/Tests/builtins/Date/Date.parse.js | 6 ++++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Libraries/LibJS/Runtime/DateConstructor.cpp b/Libraries/LibJS/Runtime/DateConstructor.cpp index 2acfc149314..1488bb0259a 100644 --- a/Libraries/LibJS/Runtime/DateConstructor.cpp +++ b/Libraries/LibJS/Runtime/DateConstructor.cpp @@ -25,7 +25,7 @@ namespace JS { GC_DEFINE_ALLOCATOR(DateConstructor); // 21.4.3.2 Date.parse ( string ), https://tc39.es/ecma262/#sec-date.parse -static double parse_simplified_iso8601(ByteString const& iso_8601) +static Optional parse_simplified_iso8601(ByteString const& iso_8601) { // 21.4.1.15 Date Time String Format, https://tc39.es/ecma262/#sec-date-time-string-format GenericLexer lexer(iso_8601); @@ -127,9 +127,8 @@ static double parse_simplified_iso8601(ByteString const& iso_8601) }; auto lex_time = [&]() { return lex_hours_minutes(hours, minutes) && (!lexer.consume_specific(':') || lex_seconds_milliseconds()) && lex_timezone(); }; - if (!lex_date() || (lexer.consume_specific('T') && !lex_time()) || !lexer.is_eof()) { - return NAN; - } + if (!lex_date() || (lexer.consume_specific('T') && !lex_time()) || !lexer.is_eof()) + return {}; // We parsed a valid date simplified ISO 8601 string. VERIFY(year.has_value()); // A valid date string always has at least a year. @@ -154,9 +153,8 @@ static double parse_date_string(VM& vm, ByteString const& date_string) if (date_string.is_empty()) return NAN; - auto value = parse_simplified_iso8601(date_string); - if (isfinite(value)) - return value; + if (auto time = parse_simplified_iso8601(date_string); time.has_value()) + return *time; // Date.parse() is allowed to accept an arbitrary number of implementation-defined formats. // FIXME: Exactly what timezone and which additional formats we should support is unclear. diff --git a/Libraries/LibJS/Tests/builtins/Date/Date.parse.js b/Libraries/LibJS/Tests/builtins/Date/Date.parse.js index 2490cefe2bc..b4be2553a8f 100644 --- a/Libraries/LibJS/Tests/builtins/Date/Date.parse.js +++ b/Libraries/LibJS/Tests/builtins/Date/Date.parse.js @@ -67,6 +67,12 @@ test("basic functionality", () => { test("time clip", () => { expect(Date.parse("+999999")).toBeNaN(); expect(Date.parse("-999999")).toBeNaN(); + + const belowMinDate = "-271821-04-19T23:59:59.999Z"; + expect(belowMinDate).toBeNaN(); + + const aboveMaxDate = "+275760-09-13T00:00:00.001Z"; + expect(aboveMaxDate).toBeNaN(); }); test("extra micro seconds extension", () => {