Temporal: a difference past a calendar's range raises RangeError instead of spinning (#3452) - #3555
Merged
Conversation
…ead of spinning Backport of sebastienros#3452 (b942c6a) to 4.x. Fixes sebastienros#3428. NonIsoCalendars.CalendarDateUntil measures a difference by walking one month at a time towards the target, and its only exit is "this step passed the target". CalendarDateAdd takes those steps, and when the conversion back to ISO left the range of the backing System.Globalization.Calendar it answered with ClampToCalendarRange, which ignored its year/month/day arguments and returned cal.MaxSupportedDateTime -- the calendar's maximum, whichever end had been overrun. Every further step of a backwards walk landed on that same date, so no step ever passed the target and the loop had no other exit. It is a CLR loop inside one interpreter step, so it crosses no statement boundary: no execution constraint can interrupt it and a CancellationToken is never observed. Out-of-range calendar arithmetic now reports itself instead of clamping. The Indian and Islamic-tabular arms answered `result ?? isoDate`, handing back their input date, which is the same no-progress answer by a different route; both now report too. CalendarDateUntil keeps a no-progress guard of its own so a clamp reintroduced below it cannot become a hang again. TemporalHelpers maps CalendarRangeException to Throw.RangeError, and realm is threaded through DifferenceISODateTime and is required on CalendarDateUntil so no call site can turn a script-visible RangeError into a CLR exception escaping Engine.Evaluate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014W5mbjGhyvgAS4pivXoc4S
This was referenced Sep 9, 2026
PatrickSt1991
pushed a commit
to Apps2Samsung/Apps2Samsung
that referenced
this pull request
Sep 14, 2026
Updated [Avalonia](https://github.com/AvaloniaUI/Avalonia/) from 11.3.20 to 11.3.22. <details> <summary>Release notes</summary> _Sourced from [Avalonia's releases](https://github.com/AvaloniaUI/Avalonia//releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/AvaloniaUI/Avalonia//commits). </details> Updated [Avalonia.Desktop](https://github.com/AvaloniaUI/Avalonia/) from 11.3.20 to 11.3.22. <details> <summary>Release notes</summary> _Sourced from [Avalonia.Desktop's releases](https://github.com/AvaloniaUI/Avalonia//releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/AvaloniaUI/Avalonia//commits). </details> Updated [Avalonia.Diagnostics](https://github.com/AvaloniaUI/Avalonia/) from 11.3.20 to 11.3.22. <details> <summary>Release notes</summary> _Sourced from [Avalonia.Diagnostics's releases](https://github.com/AvaloniaUI/Avalonia//releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/AvaloniaUI/Avalonia//commits). </details> Updated [Avalonia.Fonts.Inter](https://github.com/AvaloniaUI/Avalonia/) from 11.3.20 to 11.3.22. <details> <summary>Release notes</summary> _Sourced from [Avalonia.Fonts.Inter's releases](https://github.com/AvaloniaUI/Avalonia//releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/AvaloniaUI/Avalonia//commits). </details> Updated [Avalonia.Themes.Fluent](https://github.com/AvaloniaUI/Avalonia/) from 11.3.20 to 11.3.22. <details> <summary>Release notes</summary> _Sourced from [Avalonia.Themes.Fluent's releases](https://github.com/AvaloniaUI/Avalonia//releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/AvaloniaUI/Avalonia//commits). </details> Updated [Jint](https://github.com/sebastienros/jint) from 4.16.1 to 4.16.2. <details> <summary>Release notes</summary> _Sourced from [Jint's releases](https://github.com/sebastienros/jint/releases)._ ## 4.16.2 Jint 4.16.2 is a maintenance release from the `4.x` branch: **correctness and conformance fixes backported from `main`, and nothing that changes an existing API or an existing default.** If you are on 4.16.1 it is a drop-in update — every public signature is the one 4.16.0 shipped, on all five target frameworks, and the per-framework snapshots in `Jint.Tests.PublicInterface/Verify/` are unchanged. `main` remains 5.0.0 development; what is coming there is recorded as it lands in [`docs/v5-migration.md`](https://github.com/sebastienros/jint/blob/main/docs/v5-migration.md). ### Highlights **Failures that used to end the process, or never end.** A native error raised while a call's arguments are being evaluated is propagated instead of leaving an empty value behind, which on 4.16.1 could recurse until the process died — `decodeURIComponent` on a malformed sequence was enough (#4009). Native recursion and the forwarding paths through bound functions and proxies are guarded so a deep native chain raises a catchable error (#4007). A module graph too deep to link raises an error the host can catch instead of overflowing the stack (#3548). Temporal and Intl parsing cannot throw an uncatchable `RegexMatchTimeoutException` because the machine was busy (#3543), a Temporal difference past a calendar's range raises `RangeError` instead of spinning forever (#3555), and the process-wide Intl culture cache and Temporal zone cache are read-only and bounded, with a rejected zone no longer remembered — closing a script-driven unbounded growth (#3546). **Generators and built-ins, step by step.** A `yield*` delegation reached again by a loop both re-delegates and keeps its place: `countdown(3)` in a loop no longer hangs, and a delegating generator no longer returns the memoized first result (#3545). `Array.prototype.map` and `slice` hand a `@@species` constructor the length `ToLength` produced, and a non-callable `map` argument is a `TypeError` (#3547). A trailing NUL pads neither a numeric string nor an array index (#3552). A removed property slot is a tombstone rather than a free slot to reuse, so enumeration order survives a delete-and-readd (#3318), and `LengthOfArrayLike` no longer clamps through a `uint` overload (#3328). **Interop that answers for the right engine.** Two engines in one process no longer decide each other's conversions and operators (#3559), a host type converter's answer stays with the engine whose converter gave it (#3563), and a value the host registers on a `ShadowRealm` — and the members its wrapper builds eagerly — belong to that realm (#3557). Realm construction state is restored after nesting or a failure (#4008). Overload selection is by the arguments in hand: an operator overload is chosen that way (#3611), a `params` overload is chosen by the array's element type with a failing element declining rather than throwing (#3782), an overload the argument cannot bind to is not a match, and a host operator that throws reports what it threw (#3554). An index on a wrapped host collection is one property however it is spelled, and a member filter that hides the indexer hides it (#3562); a read-only host collection refuses a write with a JavaScript `TypeError` rather than the CLR's `NotSupportedException` (#3556). **Internationalization and Temporal.** The Persian calendar extends into proleptic years on its 33-year cycle, so the ends of Temporal's range land in the right Persian year (#4006); a calendar that counts Gregorian months writes their names (#3612); and a `-u-` extension carrying more than one key is read whole (#3613). **Errors.** Only a string-valued `stack` counts as a pre-existing stack when a `JavaScriptException` is built, so an accessor or non-string `stack` on a thrown object no longer breaks error reporting (#3677, reported by @jeske). Every change was verified failing-first against the unfixed branch on both .NET Framework and .NET 10, and the release was gated on a paired SunSpider and Dromaeo comparison against 4.16.1 on an idle machine: no row regressed outside run-to-run noise, most run 1–4 % faster. ## What's Changed * Backport: a removed property slot is a tombstone, not a free slot to reuse (#3273) by @lahma in sebastienros/jint#3318 * Backport: LengthOfArrayLike, delete the uint overload rather than clamp it (#3248) by @lahma in sebastienros/jint#3328 * Temporal and Intl parsing cannot fail because the machine was busy (#3486) by @lahma in sebastienros/jint#3543 * Backport: the process-wide Intl culture cache and Temporal zone cache are read-only and bounded, and a rejected zone is not remembered by @lahma in sebastienros/jint#3546 * Array: map and slice hand a @@species constructor the length ToLength produced (#3510) by @lahma in sebastienros/jint#3547 * Generators: a yield* delegation both re-delegates and keeps its place (backport of #3506 and #3518) by @lahma in sebastienros/jint#3545 * A module graph too deep to link raises an error the host can catch, instead of ending the process (#3415) by @lahma in sebastienros/jint#3548 * String to number: a trailing NUL pads neither a number string nor an array index (backport of #3544) by @lahma in sebastienros/jint#3552 * Interop: a host operator reports what it threw, and an overload the argument cannot bind to is not a match by @lahma in sebastienros/jint#3554 * Temporal: a difference past a calendar's range raises RangeError instead of spinning (#3452) by @lahma in sebastienros/jint#3555 * Interop: a read-only host collection refuses script with a JavaScript error, not the CLR's own (backport of #3385) by @lahma in sebastienros/jint#3556 * ShadowRealm: a value the host registers, and the members its wrapper builds eagerly, belong to that realm by @lahma in sebastienros/jint#3557 * Interop: two engines in one process do not decide each other's conversions and operators (backport of #3521 and #3526) by @lahma in sebastienros/jint#3559 * Interop: an index on a wrapped host collection is one property, and a filter that hides the indexer hides it by @lahma in sebastienros/jint#3562 * Interop: a host type converter's answer stays with the engine whose converter gave it by @lahma in sebastienros/jint#3563 * Interop: an operator overload is chosen by the arguments in hand (backport of #3578) by @lahma in sebastienros/jint#3611 * Intl: a calendar counting Gregorian months writes their names (backport of #3589) by @lahma in sebastienros/jint#3612 * Intl: a `-u-` extension carrying more than one key is read whole (backport of #3594) by @lahma in sebastienros/jint#3613 * JavaScriptException: only a string "stack" counts as a pre-existing stack (#3607 backport) by @lahma in sebastienros/jint#3677 * Interop: a params overload is chosen by the array's element type, and a failing element declines instead of throwing (#3764) by @lahma in sebastienros/jint#3782 * Backport #3751 to 4.x: Temporal: the persian calendar extends into proleptic years on the 33-year cycle by @lahma in sebastienros/jint#4006 * Backport #3922 to 4.x: Restore realm construction state after nesting or failure by @lahma in sebastienros/jint#4008 * Backport #3845 to 4.x: Propagate native errors during call argument evaluation by @lahma in sebastienros/jint#4009 * Backport #3877 to 4.x: Guard native recursion and forwarding paths by @lahma in sebastienros/jint#4007 **Full Changelog**: sebastienros/jint@v4.16.1...v4.16.2 Commits viewable in [compare view](sebastienros/jint@v4.16.1...v4.16.2). </details> Updated [Microsoft.AspNetCore](https://github.com/dotnet/aspnetcore) from 2.3.12 to 2.3.13. <details> <summary>Release notes</summary> _Sourced from [Microsoft.AspNetCore's releases](https://github.com/dotnet/aspnetcore/releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/dotnet/aspnetcore/commits). </details> Updated [Microsoft.AspNetCore.Server.Kestrel.Core](https://github.com/dotnet/aspnetcore) from 2.3.12 to 2.3.13. <details> <summary>Release notes</summary> _Sourced from [Microsoft.AspNetCore.Server.Kestrel.Core's releases](https://github.com/dotnet/aspnetcore/releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/dotnet/aspnetcore/commits). </details> Updated [System.Security.Cryptography.Xml](https://github.com/dotnet/dotnet) from 10.0.11 to 10.0.12. <details> <summary>Release notes</summary> _Sourced from [System.Security.Cryptography.Xml's releases](https://github.com/dotnet/dotnet/releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/dotnet/dotnet/commits). </details> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This was referenced Sep 14, 2026
legrab
added a commit
to legrab/pocok
that referenced
this pull request
Sep 15, 2026
Updated [Jint](https://github.com/sebastienros/jint) from 4.16.1 to 4.16.2. <details> <summary>Release notes</summary> _Sourced from [Jint's releases](https://github.com/sebastienros/jint/releases)._ ## 4.16.2 Jint 4.16.2 is a maintenance release from the `4.x` branch: **correctness and conformance fixes backported from `main`, and nothing that changes an existing API or an existing default.** If you are on 4.16.1 it is a drop-in update — every public signature is the one 4.16.0 shipped, on all five target frameworks, and the per-framework snapshots in `Jint.Tests.PublicInterface/Verify/` are unchanged. `main` remains 5.0.0 development; what is coming there is recorded as it lands in [`docs/v5-migration.md`](https://github.com/sebastienros/jint/blob/main/docs/v5-migration.md). ### Highlights **Failures that used to end the process, or never end.** A native error raised while a call's arguments are being evaluated is propagated instead of leaving an empty value behind, which on 4.16.1 could recurse until the process died — `decodeURIComponent` on a malformed sequence was enough (#4009). Native recursion and the forwarding paths through bound functions and proxies are guarded so a deep native chain raises a catchable error (#4007). A module graph too deep to link raises an error the host can catch instead of overflowing the stack (#3548). Temporal and Intl parsing cannot throw an uncatchable `RegexMatchTimeoutException` because the machine was busy (#3543), a Temporal difference past a calendar's range raises `RangeError` instead of spinning forever (#3555), and the process-wide Intl culture cache and Temporal zone cache are read-only and bounded, with a rejected zone no longer remembered — closing a script-driven unbounded growth (#3546). **Generators and built-ins, step by step.** A `yield*` delegation reached again by a loop both re-delegates and keeps its place: `countdown(3)` in a loop no longer hangs, and a delegating generator no longer returns the memoized first result (#3545). `Array.prototype.map` and `slice` hand a `@@species` constructor the length `ToLength` produced, and a non-callable `map` argument is a `TypeError` (#3547). A trailing NUL pads neither a numeric string nor an array index (#3552). A removed property slot is a tombstone rather than a free slot to reuse, so enumeration order survives a delete-and-readd (#3318), and `LengthOfArrayLike` no longer clamps through a `uint` overload (#3328). **Interop that answers for the right engine.** Two engines in one process no longer decide each other's conversions and operators (#3559), a host type converter's answer stays with the engine whose converter gave it (#3563), and a value the host registers on a `ShadowRealm` — and the members its wrapper builds eagerly — belong to that realm (#3557). Realm construction state is restored after nesting or a failure (#4008). Overload selection is by the arguments in hand: an operator overload is chosen that way (#3611), a `params` overload is chosen by the array's element type with a failing element declining rather than throwing (#3782), an overload the argument cannot bind to is not a match, and a host operator that throws reports what it threw (#3554). An index on a wrapped host collection is one property however it is spelled, and a member filter that hides the indexer hides it (#3562); a read-only host collection refuses a write with a JavaScript `TypeError` rather than the CLR's `NotSupportedException` (#3556). **Internationalization and Temporal.** The Persian calendar extends into proleptic years on its 33-year cycle, so the ends of Temporal's range land in the right Persian year (#4006); a calendar that counts Gregorian months writes their names (#3612); and a `-u-` extension carrying more than one key is read whole (#3613). **Errors.** Only a string-valued `stack` counts as a pre-existing stack when a `JavaScriptException` is built, so an accessor or non-string `stack` on a thrown object no longer breaks error reporting (#3677, reported by @jeske). Every change was verified failing-first against the unfixed branch on both .NET Framework and .NET 10, and the release was gated on a paired SunSpider and Dromaeo comparison against 4.16.1 on an idle machine: no row regressed outside run-to-run noise, most run 1–4 % faster. ## What's Changed * Backport: a removed property slot is a tombstone, not a free slot to reuse (#3273) by @lahma in sebastienros/jint#3318 * Backport: LengthOfArrayLike, delete the uint overload rather than clamp it (#3248) by @lahma in sebastienros/jint#3328 * Temporal and Intl parsing cannot fail because the machine was busy (#3486) by @lahma in sebastienros/jint#3543 * Backport: the process-wide Intl culture cache and Temporal zone cache are read-only and bounded, and a rejected zone is not remembered by @lahma in sebastienros/jint#3546 * Array: map and slice hand a @@species constructor the length ToLength produced (#3510) by @lahma in sebastienros/jint#3547 * Generators: a yield* delegation both re-delegates and keeps its place (backport of #3506 and #3518) by @lahma in sebastienros/jint#3545 * A module graph too deep to link raises an error the host can catch, instead of ending the process (#3415) by @lahma in sebastienros/jint#3548 * String to number: a trailing NUL pads neither a number string nor an array index (backport of #3544) by @lahma in sebastienros/jint#3552 * Interop: a host operator reports what it threw, and an overload the argument cannot bind to is not a match by @lahma in sebastienros/jint#3554 * Temporal: a difference past a calendar's range raises RangeError instead of spinning (#3452) by @lahma in sebastienros/jint#3555 * Interop: a read-only host collection refuses script with a JavaScript error, not the CLR's own (backport of #3385) by @lahma in sebastienros/jint#3556 * ShadowRealm: a value the host registers, and the members its wrapper builds eagerly, belong to that realm by @lahma in sebastienros/jint#3557 * Interop: two engines in one process do not decide each other's conversions and operators (backport of #3521 and #3526) by @lahma in sebastienros/jint#3559 * Interop: an index on a wrapped host collection is one property, and a filter that hides the indexer hides it by @lahma in sebastienros/jint#3562 * Interop: a host type converter's answer stays with the engine whose converter gave it by @lahma in sebastienros/jint#3563 * Interop: an operator overload is chosen by the arguments in hand (backport of #3578) by @lahma in sebastienros/jint#3611 * Intl: a calendar counting Gregorian months writes their names (backport of #3589) by @lahma in sebastienros/jint#3612 * Intl: a `-u-` extension carrying more than one key is read whole (backport of #3594) by @lahma in sebastienros/jint#3613 * JavaScriptException: only a string "stack" counts as a pre-existing stack (#3607 backport) by @lahma in sebastienros/jint#3677 * Interop: a params overload is chosen by the array's element type, and a failing element declines instead of throwing (#3764) by @lahma in sebastienros/jint#3782 * Backport #3751 to 4.x: Temporal: the persian calendar extends into proleptic years on the 33-year cycle by @lahma in sebastienros/jint#4006 * Backport #3922 to 4.x: Restore realm construction state after nesting or failure by @lahma in sebastienros/jint#4008 * Backport #3845 to 4.x: Propagate native errors during call argument evaluation by @lahma in sebastienros/jint#4009 * Backport #3877 to 4.x: Guard native recursion and forwarding paths by @lahma in sebastienros/jint#4007 **Full Changelog**: sebastienros/jint@v4.16.1...v4.16.2 Commits viewable in [compare view](sebastienros/jint@v4.16.1...v4.16.2). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details>
This was referenced Sep 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backport of #3452 to
4.x. Fixes #3428 there too — the defect predates every released 4.x, and the hangreproduces on this branch with the same shape and the same failure count as on
main.What was wrong
NonIsoCalendars.CalendarDateUntilmeasures a difference by walking one month at a time from the sourcetowards the target, and its only exit is "this step passed the target".
NonIsoCalendars.CalendarDateAddtakes those steps, and when the conversion back to ISO left the range of the backing
System.Globalization.Calendarit did not report that — it answered withClampToCalendarRange, whichignored its year, month and day arguments entirely and returned
cal.MaxSupportedDateTime:The calendar's maximum, whichever end had been overrun. So every further step of a backwards walk landed
on that same date, no step ever passed the target, and the loop had no other exit.
ChineseLunisolarCalendarspans ISO 1901-02-19 to 2101-01-28, so the target is outside it.What an embedder saw is the thread, and nothing else. It is a CLR loop inside one interpreter step, so
it crosses no statement boundary:
LimitStatementsnever counted,LimitExecutionTimenever got a check,and a
CancellationTokenwas never observed. A host that bounded untrusted script the documented way stilllost the thread, and the only way back was to end the process. Reachable from any script that can name a
chinese,dangi,hebreworpersiandate, throughuntil,sinceandtotalonPlainDate,PlainDateTime,PlainYearMonth,ZonedDateTimeandDuration.The same clamp was also answering, rather than hanging, on the addition side — with the wrong date, and with
no signal that it was wrong. Measured on unfixed
4.x:What changed
Identical in substance to #3452. Out-of-range calendar arithmetic reports itself instead of clamping.
NonISODateAddis implementation-defined and is declared as returning "either a normal completioncontaining an ISO Date Record or a throw completion"
(spec), and
CalendarDateAddraises aRangeErrorfor a result it cannot represent(spec). Both
overflowmodes report it:leaving the calendar's range is not the month-or-day overflow
constrainis allowed to clamp, because thereis no nearby valid date to clamp to — only the calendar's own boundary.
NonIsoCalendars.CalendarDateAdd—ClampToCalendarRangeis gone; theArgumentOutOfRangeExceptionfrom
cal.ToDateTimebecomes aCalendarRangeException.NonIsoCalendars.IndianCalendarDateAddandIslamicTabularCalendarDateAdd— both answeredresult ?? isoDate, handing back their input date when the conversion failed. That is the sameno-progress answer by a different route:
addreports that adding a year changed nothing, and the walktakes the same step forever. Both now report instead.
NonIsoCalendars.CalendarDateUntil— the walk keeps a no-progress guard of its own. With the three fixesabove it is unreachable today; it stays as the structural guarantee that this loop terminates, so a clamp
reintroduced anywhere below it cannot become a hang again.
TemporalHelpers.CalendarDateAdd/CalendarDateUntilmap it toThrow.RangeError.realmis threadedthrough
DifferenceISODateTimeand is now required onCalendarDateUntil, so no call site can lose itand turn a script-visible
RangeErrorinto a CLR exception escapingEngine.Evaluate.All internal; no public API change.
Divergence from the
mainPRThree adaptations, all mechanical, and none of them changes what the fix does:
ThrowCalendarArithmeticUnavailabledoes not exist on4.x. It arrived onmainin separate work,and Temporal: a month difference past the calendar's range raises RangeError instead of spinning #3452 merely added a sibling beside it. That hunk is dropped:
4.xkeeps itsthrow new NotSupportedException($"Calendar '{calendar}' not yet supported")for a calendar with noarithmetic, and only
ThrowCalendarRangeis added.using System.Diagnostics.CodeAnalysis;had to comewith it for the
[DoesNotReturn], whichmainalready had a use for in that file.CalendarDateUntilhad norealmparameter at all on4.x. Onmainit was already there asRealm? realm = nulland Temporal: a month difference past the calendar's range raises RangeError instead of spinning #3452 only made it required; here it is added, required, and threaded throughthe three call sites that lacked it —
PlainDatePrototype.DifferenceTemporalPlainDateandPlainYearMonthPrototype.DifferenceYearMonth(both pass_realm), and theweekarm ofRoundRelativeDurationinTemporalHelpers(which already held arealm). Every one had a realm athand, so nothing had to be widened to carry one.
Jint.Testsis xUnit v3 on4.x.[Test]→[Fact],[TestCase(…, TestName: …)]→[Theory]+[InlineData](the case names move into the doc comment, sinceInlineDatahas nowhere to put them),and
DedicatedThread's join timeout keeps throwingXunitExceptionrather than NUnit'sAssertionException.NonIsoCalendars.csis still one file on this branch — theNonIsoCalendars.Lunisolar.cssplit is latermainwork, after #3452 — so all four engine hunks in it applied unchanged, and the twoNonIsoCalendarsentry points #3452 wraps are still the only two callers in the assembly here.
Jint.Tests/DedicatedThread.csalso carries #3452's second half: a body starts at normal priority and isdemoted to
ThreadPriority.Lowestonly once its join has timed out, at which point it is known to be arunaway that must be kept off the cores the rest of the run needs. Starting every body at
Lowestcost a0.1 ms evaluation 2.5 s under two competitors on
main's measurement, which is what made thenet472CIleg red there.
4.xhas the same helper and the same starting priority, so it inherits the same fix.Failing-test evidence, per target framework
Jint.Tests/Runtime/NonIsoCalendarRangeTests.csruns every case on a dedicated thread with a 15-secondjoin, so a regression fails the run rather than wedging it. Against the unfixed
4.xengine (thisbranch with
Jint/reverted, test file andDedicatedThreadchange in place):net472(thenet462asset)net10.0Both frameworks fail the identical fifteen. Nine of them are the hang and account for two of those two and
a quarter minutes — each burning its whole 15-second budget in an uninterruptible CLR loop, which is exactly
what an embedder's thread was doing:
The other six are the boundary date answered as if it were the result, in a millisecond:
Test suites
One
dotnet test -c Releaserun on1cfe8c34a:Jint.TestsJint.Tests.PublicInterfaceJint.Tests.CommonScriptsJint.Tests.SourceGeneratorsJint.Tests.Test262: 102,499 passed, 0 failed, 185 skipped (102,684 total) — the branch control,unchanged. The full run reported two failures, both variants of
intl402/supportedLocalesOf-unicode-extensions-ignored.jstiming out at 34 s against the engine's own30-second default while three other test assemblies and a sibling suite shared the box. Re-run alone on the
same tree it passes in 2 s, and nothing in this change reaches
Intl.supportedLocalesOf.dotnet build -c Release: 0 errors, no new warnings.🤖 Generated with Claude Code
https://claude.ai/code/session_014W5mbjGhyvgAS4pivXoc4S