Skip to content

Backport: the process-wide Intl culture cache and Temporal zone cache are read-only and bounded, and a rejected zone is not remembered - #3546

Merged
lahma merged 3 commits into
sebastienros:4.xfrom
lahma:backport/3448-culture-cache
Sep 1, 2026
Merged

lahma merged 3 commits into
sebastienros:4.xfrom
lahma:backport/3448-culture-cache

Conversation

@lahma

@lahma lahma commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Backports three merged main fixes to 4.x, in the order they landed there. All three are about the same shape: a process-wide cache keyed on a string a script chose, shared by every engine, never evicted — and in one case handed out writable.

Backported main squash 4.x commit
#3448 Intl: the culture every engine shares is handed out read-only d6dbcfe8c c5e2f4a4d
#3462 Intl: the shared culture cache is bounded 1676c9c15 a129ea72d
#3471 Temporal: a rejected time zone identifier is not remembered 0867d36e8 9161ec51a

Together they close #3438 and #3439 on the maintenance branch.

What each one changes

#3448 — IntlUtilities cached one CultureInfo per locale tag under a comment claiming useUserOverride: false made it immutable. It does not; that flag only suppresses the Windows user regional overrides. The instance was writable and handed straight out to eleven call sites, so one future culture.NumberFormat.CurrencySymbol = … would have been one engine's write becoming another engine's formatting, on state outliving every engine that touched it. CultureInfo.ReadOnly marks the instance it is given rather than re-resolving the culture, so the reason new CultureInfo(...) is used instead of CultureInfo.GetCultureInfo(...) stands untouched, and a clone of a read-only culture or format is writable — which is what keeps DateTimeFormatConstructor and NumberFormatConstructor working unchanged.

#3462 — the same cache had no bound, and its key is a tag a script chose: ECMA-402 requires CanonicalizeLocaleList to accept a structurally valid but unknown tag rather than reject it, and 'x'.toLocaleLowerCase('en-abcd' + i) is core String.prototype on an engine that opted into nothing. It is now bounded at 256 distinct tags, cleared and refilled on overflow — the rule RegExpParseCache already uses here. A hit costs exactly what it cost before: one ConcurrentDictionary.TryGetValue, no recency list, no allocation.

#3471 — DefaultTimeZoneProvider.Instance is the provider every unconfigured engine gets, and IsValidTimeZone ended in the same ResolveTimeZone the working paths use, so every rejected identifier became a permanent entry. Rejections are no longer cached at all, which is defensible only because a miss is now cheap: the IANA naming screen checks that every /-separated component could be a TZDB name (so A/0, Europe/, Europe//London and a megabyte of text are answered from the string), the direct lookup uses TimeZoneInfo.TryFindSystemTimeZoneById instead of FindSystemTimeZoneById in a catch, and the case-insensitive fallback reads a dictionary built once instead of re-scanning every system zone. The successes are bounded at 256 too, because getTimeZoneTransition on a ZonedDateTime built from +HH:MM reaches the resolver with 1440 distinct valid spellings.

Evidence: the tests run against unfixed 4.x

Ported onto e556d274 with only the two count accessors added (no bound, no read-only, no screen), the same set fails on both legs — 9 failed / 24, identical on net10.0 and on net472, which is the leg that consumes the net462 asset:

net472 (net462 asset)net10.0
#3448
IntlTests.ACachedCultureIsReadOnly ×3 (en-US, de-DE, ar-SA)Expected culture!.IsReadOnly to be True, but found False.
#3462
ScriptSuppliedLocaleTagsDoNotGrowTheProcessWideCultureCachefound 4004 (bound 256)found 4003 (bound 256)
RequestedLocalesOfAnIntlFormatterDoNotGrowTheProcessWideCultureCachefound 4004found 4003
AnEvictedTagResolvesToTheSameCultureItDidBeforefails on the read-only half it inherits from #3448
#3471
RejectedTimeZoneIdentifiersDoNotGrowTheProcessWideCachefound 501found 1942
OffsetTimeZoneIdentifiersDoNotGrowTheProcessWideCachefound 1948found 1948
ARejectedIdentifierIsNotRememberedone rejection, +1 entry

(The two rejected-identifier counts differ only because the class shares one process-wide cache with the offset test and the runner orders them differently per leg; both are far over 256.)

With the three fixes: 46 / 46 passed on net10.0 and on net472. The four #3471 tests that cannot exist against unfixed code — they call IsPlausibleIanaName, which is the fix — are EverySystemTimeZoneIdentifierSurvivesTheSyntacticScreen (walks every zone this machine has, plus the IANA name .NET gives for each Windows id, with a counter so it can never pass vacuously), TheSyntacticScreenAcceptsEveryTzdbNameShape, TheSyntacticScreenDeclinesWhatCannotNameAZone and TheSyntacticScreenDeclinesAnAbsurdlyLongIdentifier.

Full suite, dotnet build -c Release + dotnet test -c Release, 0 warnings from the compiler

Jint.Tests               6794 / 6794 (net472)     6879 / 6879 (net10.0)
Jint.Tests.PublicInterface  1493 / 1493 (net472)     1500 / 1500 (net10.0)
Jint.Tests.CommonScripts      28 / 28   (net472)       28 / 28   (net10.0)
Jint.Tests.SourceGenerators                             52 / 52   (net10.0)
Jint.Tests.Test262        102495 passed / 0 failed / 189 skipped

The test262 figure is the branch's control figure exactly.

Divergences from main

Every source hunk applied verbatim (git apply -3, clean, all three), with two adaptations:

  • The tests are xUnit. 4.x's Jint.Tests has not taken the NUnit move, so [Test] → [Fact], [TestCase] → [InlineData], and [NonParallelizable] → [CollectionDefinition(..., DisableParallelization = true)] + [Collection(...)], which is how GarbageCollectionTests and SharedObjectShapeTests already say it here. Every assertion is unchanged.
  • net462, not net472. One comment in the TryFindSystemTimeZoneById polyfill names the target frameworks that need it; on this branch the floor is net462, matching how DefaultTimeZoneProvider.IsWindowsPlatform already words it.

Two smaller notes. ACachedCultureIsReadOnly is appended at the end of IntlTests rather than inserted where main has it — the neighbouring test there does not exist on 4.x — and IntlTests gains using System.Globalization; and using Jint.Native.Intl;, which main's copy already had. Jint/Native/Intl/IntlUtilities.cs, Jint/Native/Temporal/DefaultTimeZoneProvider.cs and Jint/Extensions/Polyfills.cs needed no other adaptation: 4.x's DefaultTimeZoneProvider is sealed where main's is extensible, but nothing in this change touches that, and 4.x's Polyfills.cs already carries the C# extension-member blocks and the char.IsAscii* backfills the screen needs.

No public API change

IntlUtilities is internal. DefaultTimeZoneProvider is public, but everything added to it — TimeZoneCacheCount, TimeZoneCacheBound, IsPlausibleIanaName — is internal, and no existing member changes its signature or its answer. What changes is what is retained and what a miss costs. The Jint.Tests.PublicInterface baselines are untouched and green on both legs.

🤖 Generated with Claude Code

https://claude.ai/code/session_014W5mbjGhyvgAS4pivXoc4S

lahma and others added 3 commits September 1, 2026 05:11
…ienros#3448)

Backport of sebastienros#3448 to 4.x.

`IntlUtilities` caches one `CultureInfo` per locale tag in a process-wide dictionary shared
by every engine and never evicted, under a comment saying `useUserOverride: false` makes it
immutable. It does not -- that flag only suppresses the Windows user regional overrides, and
`CultureInfo.ReadOnly` is what makes an instance read-only, which is exactly why the comment
inside `CreateCultureInfo` explains that `CultureInfo.GetCultureInfo` was avoided.

So the shared instance was writable and is handed straight out to eleven call sites. Nothing
writes to it today -- the two places that adjust a format clone first -- but one future
`culture.NumberFormat.CurrencySymbol = ...` on any hand-out site would be one engine's write
becoming another engine's formatting, on state that outlives every engine that touched it,
with nothing to report it.

`CultureInfo.ReadOnly` marks the instance it is given rather than re-resolving the culture,
so the reason `new CultureInfo(...)` is used stands untouched; and a clone of a read-only
culture, `DateTimeFormatInfo` or `NumberFormatInfo` is writable, which is what keeps
`DateTimeFormatConstructor` and `NumberFormatConstructor` working unchanged.

The test is the same one main carries, expressed in xUnit because 4.x's `Jint.Tests` has not
taken the NUnit move.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014W5mbjGhyvgAS4pivXoc4S
…nnot grow it (sebastienros#3462)

Backport of sebastienros#3462 to 4.x.

`IntlUtilities` keys one `CultureInfo` per locale tag in a process-wide
`ConcurrentDictionary` shared by every engine, and nothing ever evicted. The
key is a string a script chose: ECMA-402 requires `CanonicalizeLocaleList` to
accept a structurally valid but unknown tag rather than reject it, so

    for (var i = 0; i < 2000; i++) { 'x'.toLocaleLowerCase('en-abcd' + i); }

on a `new Engine()` -- core `String.prototype`, no Intl opt-in, no WebApi --
left 4003 permanent entries behind, attributable to no engine's `LimitMemory`
and outliving every engine that created them.

The cache is now bounded the way `RegExpParseCache` is: a capacity of 256
distinct tags, cleared and refilled on overflow. Clearing rather than
LRU-evicting keeps the hit path exactly what it was -- one
`ConcurrentDictionary.TryGetValue`, no bookkeeping, no allocation -- and is
thread-safe and self-healing when the working set shifts. Real scripts use a
handful of locales and fill it once.

Eviction cannot become a correctness problem here: the value is a total
function of the key, and since sebastienros#3448 the instance handed out is read-only, so
an engine still holding an evicted culture keeps one equal to whatever the next
lookup produces. `AnEvictedTagResolvesToTheSameCultureItDidBefore` pins that.

`IntlUtilities` is internal and no public signature or observable answer
changes, so there is no migration row.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014W5mbjGhyvgAS4pivXoc4S
…s no system scan (sebastienros#3471)

Backport of sebastienros#3471 to 4.x. Fixes sebastienros#3439 there as well.

`DefaultTimeZoneProvider.Instance` is the provider every unconfigured engine
gets, so its `_timeZoneCache` is process-wide in practice. `IsValidTimeZone`
ends in the same `ResolveTimeZone` the working paths use, and
`TemporalHelpers.ValidateTimeZoneId` calls it for every user-supplied zone --
so a *rejected* identifier got a permanent entry keyed on a string the script
chose, and on net8+ each one cost a full linear scan of
`TimeZoneInfo.GetSystemTimeZones()` to establish.

Rejections are no longer cached at all. A negative cache is the one an attacker
can fill for free, and a rejection here is cheap to recompute -- which is the
other half of the change:

* the IANA naming screen now checks that every '/'-separated component could be
  a TZDB name (begins with an ASCII letter, continues with letters, digits,
  '.', '_', '+' or '-', within a generous length bound), so 'A/0', 'A/1', ...
  are answered from the string with no system call at all. It only ever
  declines what the lookup below would have declined, which
  `EverySystemTimeZoneIdentifierSurvivesTheSyntacticScreen` pins against the
  zones of whatever machine runs the tests;
* the direct lookup uses `TimeZoneInfo.TryFindSystemTimeZoneById` (polyfilled
  below net8, so net462, netstandard2.0 and netstandard2.1 all get it) instead
  of `FindSystemTimeZoneById` in a `catch`, so a plausible but unknown
  identifier no longer costs a throw on the shipping asset;
* the case-insensitive fallback reads a dictionary built once from
  `GetSystemTimeZones()` instead of re-scanning every zone on each miss.

The successes are bounded as well, at 256 entries cleared and refilled on
overflow -- the rule `RegExpParseCache` uses. They need it because an offset
identifier resolves to a zone this provider manufactures rather than one the
system has, and `getTimeZoneTransition` on a ZonedDateTime built with '+HH:MM'
reaches `ResolveTimeZone` with 1440 distinct spellings.

Every answer is unchanged. The tests are the ones main carries, expressed in
xUnit because 4.x's `Jint.Tests` has not taken the NUnit move.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014W5mbjGhyvgAS4pivXoc4S
@lahma
lahma merged commit 9ccceb0 into sebastienros:4.x Sep 1, 2026
5 checks passed
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>
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>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Jint&package-manager=nuget&previous-version=4.16.1&new-version=4.16.2)](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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant