YARR JIT crash fixes for non-greedy ParenthesesSubpattern backtracking
JSTests/stress/yarr-jit-non-greedy-parentheses-backtrack.js
This commit fixes two distinct JIT crashes in YARR's non-greedy ParenthesesSubpattern backtracking, both reachable from attacker-controlled regex input. The first is an uninitialized returnAddress frame slot causing SIGBUS on ARM64E (SIGSEGV elsewhere) when a non-greedy multi-alternative group skips its body inside a FixedCount outer loop — the NestedAlternativeEnd.bt handler reads a return address that was never written because the group body was skipped. The fix initializes the returnAddress slot during NestedAlternativeBegin.
The second is more architecturally interesting: a stale ParenContext chain causing out-of-bounds input access. The ParenContext free list recycles released allocations across backtrack iterations. When restoreParenContext restores a snapshot from an earlier outer iteration, it restores the inner pattern's parenContextHead pointer — which now points to a ParenContext that was freed and recycled by a later iteration. The recycled slot contains overwritten data (match indices from a different match path), and reading those indices produces out-of-bounds access into the input string.
Forward (outer iters 1-3):
inner (a|b)*? skips → parenContextHead = null saved in each OuterCtx
Backtrack cycle A (iter 3 retry):
restoreParenContext(OuterCtx3)
inner (a|b)*? allocates → InnerCtx1
match succeeds → OuterCtx3' saved with parenContextHead → InnerCtx1
next attempt fails → inner backtracks → InnerCtx1 freed → free list
Backtrack cycle B (try iter 2):
restoreParenContext(OuterCtx2) ← original, parenContextHead = null
inner allocates from free list ← gets RECYCLED InnerCtx1
match succeeds → OuterCtx2' saved with parenContextHead → recycled InnerCtx1
iter 3 re-runs, fails
restoreParenContext(OuterCtx2') ← parenContextHead → recycled InnerCtx1
InnerCtx1 now holds overwritten data (begin/end = 73,000,000)
inner Begin.bt reads InnerCtx1 → OOB input access → SIGSEGV
The fix adds clearInnerParenContextHeadSlots — after restoreParenContext, all inner Greedy/NonGreedy parenContextHead slots are nulled out, preventing freed-context reuse through stale pointers.
Significance
Both bugs are crash-grade and reachable from regex input alone. The stale-context bug is structurally a use-after-free in the ParenContext free list — a freed allocation is recycled, overwritten by a later allocation, and then read via a stale pointer restored by restoreParenContext, with the corrupted read becoming a match index into the input string (OOB read). On non-PAC platforms, the uninitialized returnAddress bug is also worth investigating: whether the JIT stack frame layout can be predicted to place an attacker-influenced value in that slot before the save.