Diff
Modified: trunk/JSTests/ChangeLog (290281 => 290282)
--- trunk/JSTests/ChangeLog 2022-02-22 02:01:09 UTC (rev 290281)
+++ trunk/JSTests/ChangeLog 2022-02-22 02:12:13 UTC (rev 290282)
@@ -1,5 +1,15 @@
2022-02-21 Yusuke Suzuki <[email protected]>
+ [JSC] Temporal.PlainDate should validate input range
+ https://bugs.webkit.org/show_bug.cgi?id=236936
+
+ Reviewed by Darin Adler.
+
+ * stress/temporal-plaindate.js:
+ (shouldThrow):
+
+2022-02-21 Yusuke Suzuki <[email protected]>
+
[JSC] ShadowRealm wrapArgument should check exceptions
https://bugs.webkit.org/show_bug.cgi?id=236984
Modified: trunk/JSTests/stress/temporal-plaindate.js (290281 => 290282)
--- trunk/JSTests/stress/temporal-plaindate.js 2022-02-22 02:01:09 UTC (rev 290281)
+++ trunk/JSTests/stress/temporal-plaindate.js 2022-02-22 02:12:13 UTC (rev 290282)
@@ -110,6 +110,14 @@
shouldThrow(() => { new Temporal.PlainDate(2007, -Infinity, 1); }, RangeError);
shouldThrow(() => { new Temporal.PlainDate(2007, 1, Infinity); }, RangeError);
shouldThrow(() => { new Temporal.PlainDate(2007, 1, -Infinity); }, RangeError);
+shouldThrow(() => { new Temporal.PlainDate(0x43530, 9, 14); }, RangeError);
+shouldBe(String(new Temporal.PlainDate(0x43530, 9, 13)), `275760-09-13`);
+shouldThrow(() => { new Temporal.PlainDate(-0x425cd, 4, 19); }, RangeError);
+shouldBe(String(new Temporal.PlainDate(-0x425cd, 4, 20)), `-271821-04-20`);
+shouldThrow(() => { new Temporal.PlainDate(0x80000000, 1, 1); }, RangeError);
+shouldThrow(() => { new Temporal.PlainDate(-0x80000000, 1, 1); }, RangeError);
+shouldThrow(() => { new Temporal.PlainDate(0x7fffffff, 1, 1); }, RangeError);
+shouldThrow(() => { new Temporal.PlainDate(-0x7fffffff, 1, 1); }, RangeError);
let failures = [
"",
Modified: trunk/Source/_javascript_Core/ChangeLog (290281 => 290282)
--- trunk/Source/_javascript_Core/ChangeLog 2022-02-22 02:01:09 UTC (rev 290281)
+++ trunk/Source/_javascript_Core/ChangeLog 2022-02-22 02:12:13 UTC (rev 290282)
@@ -1 +1,45 @@
+2022-02-21 Yusuke Suzuki <[email protected]>
+
+ [JSC] Temporal.PlainDate should validate input range
+ https://bugs.webkit.org/show_bug.cgi?id=236936
+
+ Reviewed by Darin Adler.
+
+ Implement https://tc39.es/proposal-temporal/#sec-temporal-isodatetimewithinlimits check in
+ PlainDate to validate input range. For example, 0x7fffffff year should be rejected since
+ it is larger than ECMAScript datetime representation value. This is checked via ISODateTimeWithinLimits
+ in the spec.
+
+ We also remove isValid assertions in ExactTime. This should not be checked in these accessors, rather,
+ we should call that function when we would like to check, since PlainDate can represent a bit smaller
+ value than ExactTime's minValue (minValue - nsPerDay).
+
+ We also extend ExactTime::fromISOPartsAndOffset to handle values via Int128 to accept int32_t range years.
+ By using Int128 for nanoseconds, we can even represent int32_t max / min years. And we remove
+ `ASSERT(y >= -999999 && y <= 999999)` check since this is not necessary.
+
+ * runtime/ISO8601.cpp:
+ (JSC::ISO8601::ExactTime::fromISOPartsAndOffset):
+ (JSC::ISO8601::isDateTimeWithinLimits):
+ * runtime/ISO8601.h:
+ (JSC::ISO8601::ExactTime::ExactTime): Deleted.
+ (JSC::ISO8601::ExactTime::fromEpochSeconds): Deleted.
+ (JSC::ISO8601::ExactTime::fromEpochMilliseconds): Deleted.
+ (JSC::ISO8601::ExactTime::fromEpochMicroseconds): Deleted.
+ (JSC::ISO8601::ExactTime::epochSeconds const): Deleted.
+ (JSC::ISO8601::ExactTime::epochMilliseconds const): Deleted.
+ (JSC::ISO8601::ExactTime::epochMicroseconds const): Deleted.
+ (JSC::ISO8601::ExactTime::epochNanoseconds const): Deleted.
+ (JSC::ISO8601::ExactTime::nanosecondsFraction const): Deleted.
+ (JSC::ISO8601::ExactTime::asString const): Deleted.
+ (JSC::ISO8601::ExactTime::isValid const): Deleted.
+ (JSC::ISO8601::ExactTime::operator< const): Deleted.
+ (JSC::ISO8601::ExactTime::operator<= const): Deleted.
+ (JSC::ISO8601::ExactTime::operator== const): Deleted.
+ (JSC::ISO8601::ExactTime::operator!= const): Deleted.
+ (JSC::ISO8601::ExactTime::operator>= const): Deleted.
+ (JSC::ISO8601::ExactTime::operator> const): Deleted.
+ * runtime/TemporalPlainDate.cpp:
+ (JSC::toPlainDate):
+
== Rolled over to ChangeLog-2022-02-22 ==
Modified: trunk/Source/_javascript_Core/runtime/ISO8601.cpp (290281 => 290282)
--- trunk/Source/_javascript_Core/runtime/ISO8601.cpp 2022-02-22 02:01:09 UTC (rev 290281)
+++ trunk/Source/_javascript_Core/runtime/ISO8601.cpp 2022-02-22 02:12:13 UTC (rev 290282)
@@ -1192,23 +1192,20 @@
return true;
}
-ExactTime ExactTime::fromISOPartsAndOffset(int32_t y, uint8_t mon, uint8_t d, unsigned h, unsigned min, unsigned s, unsigned ms, unsigned micros, unsigned ns, int64_t offset)
+ExactTime ExactTime::fromISOPartsAndOffset(int32_t year, uint8_t month, uint8_t day, unsigned hour, unsigned minute, unsigned second, unsigned millisecond, unsigned microsecond, unsigned nanosecond, int64_t offset)
{
- ASSERT(y >= -999999 && y <= 999999);
- ASSERT(mon >= 1 && mon <= 12);
- ASSERT(d >= 1 && d <= 31);
- ASSERT(h <= 23);
- ASSERT(min <= 59);
- ASSERT(s <= 59);
- ASSERT(ms <= 999);
- ASSERT(micros <= 999);
- ASSERT(ns <= 999);
+ ASSERT(month >= 1 && month <= 12);
+ ASSERT(day >= 1 && day <= 31);
+ ASSERT(hour <= 23);
+ ASSERT(minute <= 59);
+ ASSERT(second <= 59);
+ ASSERT(millisecond <= 999);
+ ASSERT(microsecond <= 999);
+ ASSERT(nanosecond <= 999);
- double dateDays = dateToDaysFrom1970(y, mon - 1, d);
- double timeMs = timeToMS(h, min, s, ms);
- double utcMs = dateDays * msPerDay + timeMs;
- Int128 utcNs = static_cast<Int128>(utcMs) * 1'000'000 + micros * 1000 + ns;
- return ExactTime { utcNs - offset };
+ Int128 dateDays = static_cast<Int128>(dateToDaysFrom1970(year, month - 1, day));
+ Int128 utcNanoseconds = dateDays * nsPerDay + hour * nsPerHour + minute * nsPerMinute + second * nsPerSecond + millisecond * nsPerMillisecond + microsecond * nsPerMicrosecond + nanosecond;
+ return ExactTime { utcNanoseconds - offset };
}
using CheckedInt128 = Checked<Int128, RecordOverflow>;
@@ -1321,5 +1318,16 @@
return ExactTime { WTF::currentTimeInNanoseconds() };
}
+// https://tc39.es/proposal-temporal/#sec-temporal-isodatetimewithinlimits
+bool isDateTimeWithinLimits(int32_t year, uint8_t month, uint8_t day, unsigned hour, unsigned minute, unsigned second, unsigned millisecond, unsigned microsecond, unsigned nanosecond)
+{
+ Int128 nanoseconds = ExactTime::fromISOPartsAndOffset(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, 0).epochNanoseconds();
+ if (nanoseconds <= (ExactTime::minValue - ExactTime::nsPerDay))
+ return false;
+ if (nanoseconds >= (ExactTime::maxValue + ExactTime::nsPerDay))
+ return false;
+ return true;
+}
+
} // namespace ISO8601
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/ISO8601.h (290281 => 290282)
--- trunk/Source/_javascript_Core/runtime/ISO8601.h 2022-02-22 02:01:09 UTC (rev 290281)
+++ trunk/Source/_javascript_Core/runtime/ISO8601.h 2022-02-22 02:12:13 UTC (rev 290282)
@@ -83,6 +83,16 @@
class ExactTime {
WTF_MAKE_FAST_ALLOCATED(ExactTime);
public:
+ static constexpr Int128 dayRangeSeconds { 86400'00000000 }; // 1e8 days
+ static constexpr Int128 nsPerMicrosecond { 1000 };
+ static constexpr Int128 nsPerMillisecond { 1'000'000 };
+ static constexpr Int128 nsPerSecond { 1'000'000'000 };
+ static constexpr Int128 nsPerMinute = nsPerSecond * 60;
+ static constexpr Int128 nsPerHour = nsPerMinute * 60;
+ static constexpr Int128 nsPerDay = nsPerHour * 24;
+ static constexpr Int128 minValue = -dayRangeSeconds * nsPerSecond;
+ static constexpr Int128 maxValue = dayRangeSeconds * nsPerSecond;
+
constexpr ExactTime() = default;
constexpr ExactTime(const ExactTime&) = default;
constexpr explicit ExactTime(Int128 epochNanoseconds) : m_epochNanoseconds(epochNanoseconds) { }
@@ -103,22 +113,18 @@
int64_t epochSeconds() const
{
- ASSERT(isValid());
return static_cast<int64_t>(m_epochNanoseconds / ExactTime::nsPerSecond);
}
int64_t epochMilliseconds() const
{
- ASSERT(isValid());
return static_cast<int64_t>(m_epochNanoseconds / ExactTime::nsPerMillisecond);
}
int64_t epochMicroseconds() const
{
- ASSERT(isValid());
return static_cast<int64_t>(m_epochNanoseconds / ExactTime::nsPerMicrosecond);
}
constexpr Int128 epochNanoseconds() const
{
- ASSERT(isValid());
return m_epochNanoseconds;
}
@@ -177,15 +183,6 @@
static ExactTime now();
private:
- static constexpr Int128 dayRangeSeconds { 86400'00000000 }; // 1e8 days
- static constexpr Int128 nsPerMicrosecond { 1000 };
- static constexpr Int128 nsPerMillisecond { 1'000'000 };
- static constexpr Int128 nsPerSecond { 1'000'000'000 };
- static constexpr Int128 nsPerMinute = nsPerSecond * 60;
- static constexpr Int128 nsPerHour = nsPerMinute * 60;
- static constexpr Int128 minValue = -dayRangeSeconds * nsPerSecond;
- static constexpr Int128 maxValue = dayRangeSeconds * nsPerSecond;
-
static void asStringImpl(StringBuilder& builder, Int128 value)
{
if (value > 9)
@@ -308,5 +305,7 @@
std::optional<ExactTime> parseInstant(StringView);
+bool isDateTimeWithinLimits(int32_t year, uint8_t month, uint8_t day, unsigned hour, unsigned minute, unsigned second, unsigned millisecond, unsigned microsecond, unsigned nanosecond);
+
} // namespace ISO8601
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/TemporalPlainDate.cpp (290281 => 290282)
--- trunk/Source/_javascript_Core/runtime/TemporalPlainDate.cpp 2022-02-22 02:01:09 UTC (rev 290281)
+++ trunk/Source/_javascript_Core/runtime/TemporalPlainDate.cpp 2022-02-22 02:12:13 UTC (rev 290282)
@@ -89,22 +89,38 @@
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
- double year = duration.years();
- double month = duration.months();
- double day = duration.days();
- if (!(month >= 1 && month <= 12)) {
+ double yearDouble = duration.years();
+ double monthDouble = duration.months();
+ double dayDouble = duration.days();
+
+ if (!isInBounds<int32_t>(yearDouble)) {
+ throwRangeError(globalObject, scope, "year is out of range"_s);
+ return { };
+ }
+ int32_t year = static_cast<int32_t>(yearDouble);
+
+ if (!(monthDouble >= 1 && monthDouble <= 12)) {
throwRangeError(globalObject, scope, "month is out of range"_s);
return { };
}
- double daysInMonth = ISO8601::daysInMonth(static_cast<int32_t>(year), static_cast<unsigned>(month));
- if (!(day >= 1 && day <= daysInMonth)) {
+ unsigned month = static_cast<unsigned>(monthDouble);
+
+ double daysInMonth = ISO8601::daysInMonth(year, month);
+ if (!(dayDouble >= 1 && dayDouble <= daysInMonth)) {
throwRangeError(globalObject, scope, "day is out of range"_s);
return { };
}
+ unsigned day = static_cast<unsigned>(dayDouble);
+
+ if (!ISO8601::isDateTimeWithinLimits(year, month, day, 0, 0, 0, 0, 0, 0)) {
+ throwRangeError(globalObject, scope, "date time is out of range of ECMAScript representation"_s);
+ return { };
+ }
+
return ISO8601::PlainDate {
- static_cast<int32_t>(year),
- static_cast<unsigned>(month),
- static_cast<unsigned>(day)
+ year,
+ month,
+ day
};
}
Modified: trunk/Source/WTF/ChangeLog (290281 => 290282)
--- trunk/Source/WTF/ChangeLog 2022-02-22 02:01:09 UTC (rev 290281)
+++ trunk/Source/WTF/ChangeLog 2022-02-22 02:12:13 UTC (rev 290282)
@@ -1,3 +1,16 @@
+2022-02-21 Yusuke Suzuki <[email protected]>
+
+ [JSC] Temporal.PlainDate should validate input range
+ https://bugs.webkit.org/show_bug.cgi?id=236936
+
+ Reviewed by Darin Adler.
+
+ Add code to allow dataLog(Int128).
+
+ * wtf/Int128.cpp:
+ (WTF::printInternal):
+ * wtf/Int128.h:
+
2022-02-18 Devin Rousso <[email protected]>
[iOS] Safari can sometimes hang while printing due to sync IPC
Modified: trunk/Source/WTF/wtf/Int128.cpp (290281 => 290282)
--- trunk/Source/WTF/wtf/Int128.cpp 2022-02-22 02:01:09 UTC (rev 290281)
+++ trunk/Source/WTF/wtf/Int128.cpp 2022-02-22 02:12:13 UTC (rev 290282)
@@ -23,6 +23,9 @@
#include <string>
#include <type_traits>
#include <wtf/MathExtras.h>
+#include <wtf/PrintStream.h>
+#include <wtf/Vector.h>
+#include <wtf/text/IntegerToStringConversion.h>
namespace WTF {
@@ -318,6 +321,29 @@
return os << rep;
}
+void printInternal(PrintStream& out, UInt128 value)
+{
+ auto vector = numberToStringUnsigned<Vector<LChar, 50>>(value);
+ vector.append('\0');
+ out.printf("%s", bitwise_cast<const char*>(vector.data()));
+}
+
+void printInternal(PrintStream& out, Int128 value)
+{
+ if (value >= 0) {
+ printInternal(out, static_cast<UInt128>(value));
+ return;
+ }
+ UInt128 positive;
+ if (value == std::numeric_limits<Int128>::min())
+ positive = static_cast<UInt128>(0x8000'0000'0000'0000ULL) << 64;
+ else
+ positive = -value;
+ auto vector = numberToStringUnsigned<Vector<LChar, 50>>(positive);
+ vector.append('\0');
+ out.printf("-%s", bitwise_cast<const char*>(vector.data()));
+}
+
} // namespace WTF
namespace std {
Modified: trunk/Source/WTF/wtf/Int128.h (290281 => 290282)
--- trunk/Source/WTF/wtf/Int128.h 2022-02-22 02:01:09 UTC (rev 290281)
+++ trunk/Source/WTF/wtf/Int128.h 2022-02-22 02:12:13 UTC (rev 290282)
@@ -55,6 +55,7 @@
namespace WTF {
class Int128Impl;
+class PrintStream;
// UInt128Impl
//
@@ -1263,6 +1264,9 @@
using Int128 = Int128Impl;
#endif
+WTF_EXPORT_PRIVATE void printInternal(PrintStream&, UInt128);
+WTF_EXPORT_PRIVATE void printInternal(PrintStream&, Int128);
+
} // namespace WTF
using WTF::Int128;