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

Reply via email to