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.
This commit is contained in:
Timothy Flynn 2024-11-26 11:05:57 -05:00 committed by Tim Flynn
commit fc6155cf2c
Notes: github-actions[bot] 2024-11-26 21:57:31 +00:00
2 changed files with 11 additions and 7 deletions

View file

@ -25,7 +25,7 @@ namespace JS {
GC_DEFINE_ALLOCATOR(DateConstructor); GC_DEFINE_ALLOCATOR(DateConstructor);
// 21.4.3.2 Date.parse ( string ), https://tc39.es/ecma262/#sec-date.parse // 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<double> parse_simplified_iso8601(ByteString const& iso_8601)
{ {
// 21.4.1.15 Date Time String Format, https://tc39.es/ecma262/#sec-date-time-string-format // 21.4.1.15 Date Time String Format, https://tc39.es/ecma262/#sec-date-time-string-format
GenericLexer lexer(iso_8601); 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(); }; 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()) { if (!lex_date() || (lexer.consume_specific('T') && !lex_time()) || !lexer.is_eof())
return NAN; return {};
}
// We parsed a valid date simplified ISO 8601 string. // We parsed a valid date simplified ISO 8601 string.
VERIFY(year.has_value()); // A valid date string always has at least a year. 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()) if (date_string.is_empty())
return NAN; return NAN;
auto value = parse_simplified_iso8601(date_string); if (auto time = parse_simplified_iso8601(date_string); time.has_value())
if (isfinite(value)) return *time;
return value;
// Date.parse() is allowed to accept an arbitrary number of implementation-defined formats. // 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. // FIXME: Exactly what timezone and which additional formats we should support is unclear.

View file

@ -67,6 +67,12 @@ test("basic functionality", () => {
test("time clip", () => { test("time clip", () => {
expect(Date.parse("+999999")).toBeNaN(); expect(Date.parse("+999999")).toBeNaN();
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", () => { test("extra micro seconds extension", () => {