Applying a large quantifier to a zero-width lookahead causes ecma_regexp_run to recurse once per quantifier iteration. Because the lookahead consumes no input, the engine never makes forward progress and recurses ~10,000 times before overflowing the native stack. There is no recursion-depth counter in the regex engine's backtracking loop.
Trigger (minimal):
/(?:(?=x)){10000}xyz/.exec('xyz');
Crash type: stack-overflow (SIGABRT / rc=1)
Component: jerry-core/ecma/operations/ecma-regexp-object.c, ecma_regexp_run
Note this is probably the same issue as #5265
JerryScript revision
git hash b706935 on master branch
Build platform
Ubuntu 24.04.4 LTS (Linux 6.8.0-106-generic x86_64)
Build steps
tools/build.py --builddir build-asan --build-type Debug \
--compile-flag=-fsanitize=address \
--compile-flag=-fno-omit-frame-pointer \
--compile-flag=-g \
--linker-flag=-fsanitize=address
Test case
echo "/(?:(?=x)){10000}xyz/.exec('xyz');" \
| ASAN_OPTIONS=halt_on_error=0 build-asan/bin/jerry -
Output
==ERROR: AddressSanitizer: stack-overflow on address 0x7fff5f3baf18
(pc 0x...05393fd2 bp 0x7fff5f3bb2c0 sp 0x7fff5f3baef0 T0)
Backtrace
#0 ecma_regexp_run ecma-regexp-object.c:535 ← stack limit hit here
#1 ecma_regexp_run ecma-regexp-object.c:778 ┐
#2 ecma_regexp_run ecma-regexp-object.c:1238 │ alternating pair,
#3 ecma_regexp_run ecma-regexp-object.c:778 │ repeats ~120×
#4 ecma_regexp_run ecma-regexp-object.c:1238 ┘
... [truncated — frames #1–#246 are the same two call sites]
SUMMARY: AddressSanitizer: stack-overflow
ecma-regexp-object.c:535 in ecma_regexp_run
The two recursive call sites are:
- line 778 — quantifier iteration dispatch: calls
ecma_regexp_run for each repetition of the {N} quantifier.
- line 1238 — lookahead dispatch: calls
ecma_regexp_run to evaluate the (?=x) sub-expression.
Because (?=x) is zero-width, the quantifier never makes forward progress in the input string, so every one of the 10,000 iterations produces a recursive call. With ~120 frames available before native stack exhaustion, the overflow occurs roughly 83× deeper than any guard could catch.
Expected behavior
ecma_regexp_run should maintain a recursion depth counter and throw a RangeError when a configurable limit is exceeded. An alternative is to convert quantifier dispatch from recursion to an explicit loop for the common zero-width case, eliminating unbounded stack growth entirely.
Applying a large quantifier to a zero-width lookahead causes
ecma_regexp_runto recurse once per quantifier iteration. Because the lookahead consumes no input, the engine never makes forward progress and recurses ~10,000 times before overflowing the native stack. There is no recursion-depth counter in the regex engine's backtracking loop.Trigger (minimal):
Crash type: stack-overflow (SIGABRT / rc=1)
Component:
jerry-core/ecma/operations/ecma-regexp-object.c,ecma_regexp_runNote this is probably the same issue as #5265
JerryScript revision
git hash b706935 on master branch
Build platform
Ubuntu 24.04.4 LTS (Linux 6.8.0-106-generic x86_64)
Build steps
Test case
Output
Backtrace
The two recursive call sites are:
ecma_regexp_runfor each repetition of the{N}quantifier.ecma_regexp_runto evaluate the(?=x)sub-expression.Because
(?=x)is zero-width, the quantifier never makes forward progress in the input string, so every one of the 10,000 iterations produces a recursive call. With ~120 frames available before native stack exhaustion, the overflow occurs roughly 83× deeper than any guard could catch.Expected behavior
ecma_regexp_runshould maintain a recursion depth counter and throw aRangeErrorwhen a configurable limit is exceeded. An alternative is to convert quantifier dispatch from recursion to an explicit loop for the common zero-width case, eliminating unbounded stack growth entirely.