Commit b7d4839876 for perl

commit b7d4839876122b66a95cb16b474368e80882a59c
Author: Richard Leach <rich+perl@hyphen-dash-hyphen.info>
Date:   Wed Oct 7 21:02:50 2026 +0000

    study_chunk: outer is_inf must not bleed into an inner CURLY

    `Perl_study_chunk` has `is_inf` and `is_inf_internal`. Both signify the
    presence of something, such as a `PLUS` (e.g. `x+`), that could
    (theoretically) match infinitely long strings.

    The difference is:
    * `is_inf` - a something in _the pattern_ compiled thus far
    * `is_inf_internal` - a something in _just this chunk_

    If any chunk sets `is_inf_internal`, that propagates into `is_inf`.

    While protecting against integer overflows,
    9b139d09af7013f395939ac80e537edd55bb404a inadvertently used `is_inf`
    rather than `is_inf_internal` in the `CURLY` studying code.

    In GH #24915's example: `"xxbbbb" =~ /x+(?:b{2}){2}/`, the leading
    `x+` correctly caused `is_inf` to be set, but the bug meant that
    the `b{2}` was erroneously treated as if it could match infinitely.
    That then resulted in the taking of a wrong branch, leading to
    _intuit_ being erroneously instructed to start searching for the
    `xbb` substring from position 2, rather than position 0.

    This commit changes the `is_inf` in the `CURLY` branch into
    `is_inf_internal`.

diff --git a/pod/perldelta.pod b/pod/perldelta.pod
index 3ca7c695f1..ac2cd7fa57 100644
--- a/pod/perldelta.pod
+++ b/pod/perldelta.pod
@@ -441,6 +441,15 @@ all consecutive characters that had the same first I<byte> were skipped.

 =item *

+Regular expression compilation could have mistaken the width of a
+quantified subpattern (e.g. C<b{2}>) when a potentially infinite
+qualifier (e.g. C<+>) occured earlier in the pattern. This could lead to
+viable match candidates at the start of the target string being missed.
+
+[GH #24915]
+
+=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/regcomp_study.c b/regcomp_study.c
index d152e69c0a..0ff4177ee7 100644
--- a/regcomp_study.c
+++ b/regcomp_study.c
@@ -2620,7 +2620,9 @@ Perl_study_chunk(pTHX_
                 is_inf_internal |= deltanext == OPTIMIZE_INFTY
                          || (maxcount == REG_INFTY && minnext + deltanext > 0);
                 is_inf |= is_inf_internal;
-                if (is_inf) {
+
+                /* GH#24915: "is this chunk infinite?" (not: "Is the pattern infinite?") */
+                if (is_inf_internal) {
                     delta = OPTIMIZE_INFTY;
                 } else {
                     delta += (minnext + deltanext) * maxcount
diff --git a/t/re/re_tests b/t/re/re_tests
index 50aa20a4f3..3abcc0ef42 100644
--- a/t/re/re_tests
+++ b/t/re/re_tests
@@ -2275,6 +2275,9 @@ z|(?:(?:a(*SKIP)b|ac)|a(*COMMIT)b)|x(*THEN)y|a	aab	n	-	-	-	extra sibling before
 (?:(?:ab(?=c)c|ad(?=e)e)|af)|x(*THEN)y|a	abc	y	$&	abc	-	lookahead continuation in first trie word
 (?:(?:ab(?=c)c|ad(?=e)e)|af)|x(*THEN)y|a	ade	y	$&	ade	-	lookahead continuation in second trie word

+# GH #24915
+x+(?:b{2}){2}	xxbbbb	y	$&	xxbbbb	-	quantified sub-pattern after PLUS
+
 # GH24916
 \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