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