Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 95d80761e6761f6c0732628bab19119917c798c7
https://github.com/WebKit/WebKit/commit/95d80761e6761f6c0732628bab19119917c798c7
Author: Yusuke Suzuki <[email protected]>
Date: 2026-06-03 (Wed, 03 Jun 2026)
Changed paths:
A JSTests/stress/regexp-nongreedy-varcount-content-backtrack.js
M Source/JavaScriptCore/yarr/YarrInterpreter.cpp
M Source/JavaScriptCore/yarr/YarrJIT.cpp
Log Message:
-----------
[YARR] Fix NonGreedy backtracking
https://bugs.webkit.org/show_bug.cgi?id=316180
rdar://178590766
Reviewed by Keith Miller.
This is a pre-existing bug in NonGreedy parentheses handling in
YarrJIT, but since we applied the same mechanism to Variable Count
NonGreedy matching, we now also have the issue for them too.
1. YarrJIT ParenthesesSubpatternBegin.bt
Previously the NonGreedy case shared the Greedy "accept fewer" path and treated
a zero remaining count as a complete failure, so it does not retry the latest
iteration to content-backtrack a previously-completed iteration and re-expand
from there. As a result the JIT missed matches that require redistributing the
iterations.
This patch fixes it so that the NonGreedy case pops the latest iteration and
jumps
to the previous iteration's content-backtrack entry, restoring frame.beginIndex
to
that iteration's begin so END.bt's progress check can re-expand after the
iteration
is shrunk. It propagates a complete failure only when there is no earlier
iteration
left.
2. Yarr interpreter backtrackParentheses
NonGreedy did not enforce quantityMinCount after a successful content backtrack:
it returned Match without refilling, so it could accept fewer than min
iterations, e.g. /(?<=Q)(?:xy|x){2,3}?yxw/.exec("Qxyxwab") wrongly matched
"xyxw". It now refills back up to min before accepting, mirroring the Greedy
case.
Retrying an iteration's content used matchNonZeroDisjunction even for a
mandatory iteration (count <= min). According to RepeatMatcher[1], the
empty-match
rejection only applies to iterations beyond the minimum, so a mandatory
iteration may
match zero-length. Step 2-b is making zero-length-matching a failure only when
min = 0.
Both the Greedy and NonGreedy content-retry sites now use matchDisjunction when
count <= min.
[1]:
https://tc39.es/ecma262/#sec-runtime-semantics-repeatmatcher-abstract-operation
Test: JSTests/stress/regexp-nongreedy-varcount-content-backtrack.js
* JSTests/stress/regexp-nongreedy-varcount-content-backtrack.js: Added.
(run):
(check):
(check.c):
(check.Q):
(check.a):
(check.x):
* Source/JavaScriptCore/yarr/YarrInterpreter.cpp:
(JSC::Yarr::Interpreter::matchParentheses):
(JSC::Yarr::Interpreter::backtrackParentheses):
(JSC::Yarr::Interpreter::refillParenthesesContextsToMinCount):
* Source/JavaScriptCore/yarr/YarrJIT.cpp:
Canonical link: https://commits.webkit.org/314506@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications