This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
regexec.c: fix #129903: forbid empty pattern in regex code block
authorYves Orton <demerphq@gmail.com>
Tue, 18 Oct 2016 11:11:49 +0000 (13:11 +0200)
committerYves Orton <demerphq@gmail.com>
Wed, 19 Oct 2016 11:28:52 +0000 (13:28 +0200)
PL_curpm provides access to the data needed to implement
the regex magic vars like $1 and $&. These vars are defined
to reference the last successfully matched pattern, or when
in regex code blocks (?{ ... }) and (??{ ... }), they
should refer to the currently executing pattern.

Unfortunately this collides with its use to implement the
empty pattern special behavior, which requires /just/
"the last successfully matched pattern" everwhere.

This meant that a pattern match like /(?{ s!!! })/ will
infinitely recurse. Fixing this would be difficult, on
the other hand detecting it is not, so we can convert
the infinite recursion/stack overflow into a normal
exception.

pod/perldiag.pod
pp_ctl.c
pp_hot.c

index 6b42a00..2e3496f 100644 (file)
@@ -6916,6 +6916,13 @@ separated by commas, not just aligned on a line.
 it may skip items, or visit items more than once.  Consider using
 C<keys()> instead of C<each()>.
 
+=item Use of the empty pattern inside of a regex code block is forbidden
+
+(F) You tried to use the empty pattern inside of a regex code block,
+for instance C</(?{ s!!! })/>. Currently for implementation reasons
+this is forbidden. Generally you can rewrite code that uses the empty
+pattern with the appropriate use of C<qr//>.
+
 =item Use of := for an empty attribute list is not allowed
 
 (F) The construction C<my $x := 42> used to parse as equivalent to
index 87c669d..b84588c 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -162,8 +162,13 @@ PP(pp_regcomp)
 #if !defined(USE_ITHREADS)
     /* can't change the optree at runtime either */
     /* PMf_KEEP is handled differently under threads to avoid these problems */
-    if (!RX_PRELEN(PM_GETRE(pm)) && PL_curpm)
+    /* Handle empty pattern */
+    if (!RX_PRELEN(PM_GETRE(pm)) && PL_curpm) {
+        if (PL_curpm == PL_reg_curpm)
+            croak("Use of the empty pattern inside of "
+                  "a regex code block is forbidden");
        pm = PL_curpm;
+    }
     if (pm->op_pmflags & PMf_KEEP) {
        pm->op_private &= ~OPpRUNTIME;  /* no point compiling again */
        cLOGOP->op_first->op_next = PL_op->op_next;
index ab59096..ea264cc 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1763,8 +1763,10 @@ PP(pp_match)
 
     /* empty pattern special-cased to use last successful pattern if
        possible, except for qr// */
-    if (!ReANY(rx)->mother_re && !RX_PRELEN(rx)
-     && PL_curpm) {
+    if (!ReANY(rx)->mother_re && !RX_PRELEN(rx) && PL_curpm) {
+        if (PL_curpm == PL_reg_curpm)
+            croak("Use of the empty pattern inside of "
+                  "a regex code block is forbidden");
        pm = PL_curpm;
        rx = PM_GETRE(pm);
     }
@@ -2960,8 +2962,11 @@ PP(pp_subst)
                                   position, once with zero-length,
                                   second time with non-zero. */
 
-    if (!RX_PRELEN(rx) && PL_curpm
-     && !ReANY(rx)->mother_re) {
+    /* handle the empty pattern */
+    if (!RX_PRELEN(rx) && PL_curpm && !ReANY(rx)->mother_re) {
+        if (PL_curpm == PL_reg_curpm)
+            croak("Use of the empty pattern inside of "
+                  "a regex code block is forbidden");
        pm = PL_curpm;
        rx = PM_GETRE(pm);
     }