Commit b27da4016d for perl

commit b27da4016d599e83fbfc511ff49b1004c46e1f0a
Author: Richard Leach <rich+perl@hyphen-dash-hyphen.info>
Date:   Fri Oct 9 09:44:18 2026 +0000

    regexec.c: CURLY* nodes must clear minmod before shortcut exits

    GH #24926 showed that `"aaaa" =~ /(?:x??\x{100})*a+/` matches `a` when it
    should match `aaaa`. This was because the non-greedy quantifier attached
    to `x??` incorrectly bled over to affect `a+`.

    Specifically, the `minmod` flag - which indicates that a non-greedy match
    should be performed - was not cleared by some CURLY* regnodes prior to an
    early `sayNO` (and similar) jump following an unsuccessful match.
    (This bug was inadvertently introduced in 5.18.0.)

    This commit adds `minmod = 0` to what look like the affected cases.

diff --git a/pod/perldelta.pod b/pod/perldelta.pod
index 6206d81138..e51767a1d2 100644
--- a/pod/perldelta.pod
+++ b/pod/perldelta.pod
@@ -448,6 +448,14 @@ viable match candidates at the start of the target string being missed.

 =item *

+Following an unsuccessful earlier non-greedy match, a regular expression
+intended to perform a separate I<greedy> match could have instead
+performed a I<non-greedy> match because of skipped flag clearance.
+
+[GH #24926]
+
+=item *
+
 In some cases warnings that occurred while using unpack on an invalid
 UTF-8 marked string would result in an invalid free.  [GH #24913]

diff --git a/regexec.c b/regexec.c
index a8860d6ea8..92ca01eeb2 100644
--- a/regexec.c
+++ b/regexec.c
@@ -9696,9 +9696,11 @@ NULL
             /* handle the single-char capture called as a GOSUB etc */
             if (EVAL_CLOSE_PAREN_IS_TRUE(cur_eval,(U32)ST.paren))
             {
+                minmod = 0;
                 char *li = locinput;
-                if (!regrepeat(rex, &li, scan, loceol, reginfo, 1))
+                if (!regrepeat(rex, &li, scan, loceol, reginfo, 1)) {
                     sayNO;
+                }
                 SET_locinput(li);
                 goto fake_end;
             }
@@ -9740,6 +9742,7 @@ NULL
                         if (! S_setup_EXACTISH_ST(aTHX_ text_node,
                                                         &ST.Binfo, reginfo))
                         {
+                            minmod = 0;
                             sayNO;
                         }
                     }
diff --git a/t/re/re_tests b/t/re/re_tests
index 3abcc0ef42..1f3cc29d82 100644
--- a/t/re/re_tests
+++ b/t/re/re_tests
@@ -2282,6 +2282,12 @@ x+(?:b{2}){2}	xxbbbb	y	$&	xxbbbb	-	quantified sub-pattern after PLUS
 \x{e0}+j	\x{e0}\x{e9}\x{e0}j	y	$&	\x{e0}j
 \x{e0}+j	\x{e0}\x{e9}\x{e0}\x{e0}j	y	$&	\x{e0}\x{e0}j

+# GH #24926
+(?:x??\x{100})*a+	aaaa	y	$&	aaaa	-	minmod cleared by CURLY
+(?:(x)??\x{100})*a+	aaaa	y	$&	aaaa	-	minmod cleared by CURLYN
+(?:x+?\x{100})*a+	aaaa	y	$&	aaaa	-	minmod cleared by PLUS
+(?:x*?\x{100})*a+	aaaa	y	$&	aaaa	-	minmod cleared by STAR
+
 # Keep these lines at the end of the file
 # pat	string	y/n/etc	expr	expected-expr	skip-reason	comment
 # vim: softtabstop=0 noexpandtab