93f7a1d
From 170c919fc4986a85062e9292e4cfed24771d2224 Mon Sep 17 00:00:00 2001
93f7a1d
From: David Mitchell <davem@iabyn.com>
93f7a1d
Date: Tue, 19 Mar 2019 10:58:46 +0000
93f7a1d
Subject: [PATCH] handle scope error in qr/\(?{/
93f7a1d
MIME-Version: 1.0
93f7a1d
Content-Type: text/plain; charset=UTF-8
93f7a1d
Content-Transfer-Encoding: 8bit
93f7a1d
93f7a1d
RT #133879
93f7a1d
93f7a1d
In this code:
93f7a1d
93f7a1d
    BEGIN {$^H = 0x10000 }; # HINT_NEW_RE
93f7a1d
    qr/\(?{/
93f7a1d
93f7a1d
When the toker sees the 'qr', it looks ahead and thinks that the
93f7a1d
pattern *might* contain code blocks, so creates a new anon sub to wrap
93f7a1d
compilation of the pattern in (so that any code blocks get compiled as
93f7a1d
part of the anon sub rather than the main body of the code).
93f7a1d
93f7a1d
Normally at the end of parsing the qr construct, the parser notes that
93f7a1d
no code blocks were found, and throws the unneeded CV away and
93f7a1d
restores the old PL_compcv (via a LEAVE_SCOPE). This false positive is
93f7a1d
normal and is expected in the relevant code paths.
93f7a1d
93f7a1d
However, setting the HINT_NEW_RE  (which indicates that
93f7a1d
overload::constant is present for qr// but with no overloaded function
93f7a1d
actually present) causes an error to be raised. The parser does error
93f7a1d
recovery and continues.
93f7a1d
93f7a1d
However, v5.25.9-148-g7c44985626 added a test to not bother compiling a
93f7a1d
pattern if the parser is in an errored state, which again is fine,
93f7a1d
except it turns out that if this branch is taken, it skips the 'restore
93f7a1d
the old PL_compcv' code, leading to the wrong value for PL_compcv when
93f7a1d
ops are freed.
93f7a1d
93f7a1d
The fix is simple: move the "skip if errored" test to after PL_compcv
93f7a1d
has been restored.
93f7a1d
93f7a1d
Signed-off-by: Petr Písař <ppisar@redhat.com>
93f7a1d
---
93f7a1d
 op.c                  | 20 ++++++++++++++------
93f7a1d
 t/re/reg_eval_scope.t | 14 +++++++++++++-
93f7a1d
 2 files changed, 27 insertions(+), 7 deletions(-)
93f7a1d
93f7a1d
diff --git a/op.c b/op.c
93f7a1d
index 1f7ae3e610..afee9fcf02 100644
93f7a1d
--- a/op.c
93f7a1d
+++ b/op.c
93f7a1d
@@ -7082,11 +7082,6 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl, UV flags, I32 floor)
93f7a1d
             rx_flags |= RXf_SPLIT;
93f7a1d
         }
93f7a1d
 
93f7a1d
-        /* Skip compiling if parser found an error for this pattern */
93f7a1d
-        if (pm->op_pmflags & PMf_HAS_ERROR) {
93f7a1d
-            return o;
93f7a1d
-        }
93f7a1d
-
93f7a1d
 	if (!has_code || !eng->op_comp) {
93f7a1d
 	    /* compile-time simple constant pattern */
93f7a1d
 
93f7a1d
@@ -7123,6 +7118,11 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl, UV flags, I32 floor)
93f7a1d
 		pm->op_pmflags &= ~PMf_HAS_CV;
93f7a1d
 	    }
93f7a1d
 
93f7a1d
+            /* Skip compiling if parser found an error for this pattern */
93f7a1d
+            if (pm->op_pmflags & PMf_HAS_ERROR) {
93f7a1d
+                return o;
93f7a1d
+            }
93f7a1d
+
93f7a1d
 	    PM_SETRE(pm,
93f7a1d
 		eng->op_comp
93f7a1d
 		    ? eng->op_comp(aTHX_ NULL, 0, expr, eng, NULL, NULL,
93f7a1d
@@ -7134,7 +7134,15 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl, UV flags, I32 floor)
93f7a1d
 	}
93f7a1d
 	else {
93f7a1d
 	    /* compile-time pattern that includes literal code blocks */
93f7a1d
-	    REGEXP* re = eng->op_comp(aTHX_ NULL, 0, expr, eng, NULL, NULL,
93f7a1d
+
93f7a1d
+	    REGEXP* re;
93f7a1d
+
93f7a1d
+            /* Skip compiling if parser found an error for this pattern */
93f7a1d
+            if (pm->op_pmflags & PMf_HAS_ERROR) {
93f7a1d
+                return o;
93f7a1d
+            }
93f7a1d
+
93f7a1d
+	    re = eng->op_comp(aTHX_ NULL, 0, expr, eng, NULL, NULL,
93f7a1d
 			rx_flags,
93f7a1d
 			(pm->op_pmflags |
93f7a1d
 			    ((PL_hints & HINT_RE_EVAL) ? PMf_USE_RE_EVAL : 0))
93f7a1d
diff --git a/t/re/reg_eval_scope.t b/t/re/reg_eval_scope.t
93f7a1d
index 25b90b6482..3bf937d251 100644
93f7a1d
--- a/t/re/reg_eval_scope.t
93f7a1d
+++ b/t/re/reg_eval_scope.t
93f7a1d
@@ -12,7 +12,7 @@ BEGIN {
93f7a1d
     }
93f7a1d
 }
93f7a1d
 
93f7a1d
-plan 48;
93f7a1d
+plan 49;
93f7a1d
 
93f7a1d
 fresh_perl_is <<'CODE', '781745', {}, '(?{}) has its own lexical scope';
93f7a1d
  my $x = 7; my $a = 4; my $b = 5;
93f7a1d
@@ -371,3 +371,15 @@ SKIP: {
93f7a1d
     f3();
93f7a1d
     is ($s, \&f3, '__SUB__ qr multi');
93f7a1d
 }
93f7a1d
+
93f7a1d
+# RT #133879
93f7a1d
+# ensure scope is properly restored when there's an error compiling a
93f7a1d
+# "looks a bit like it has (?{}) but doesn't" qr//
93f7a1d
+
93f7a1d
+fresh_perl_like <<'CODE',
93f7a1d
+    BEGIN {$^H = 0x10000 }; # HINT_NEW_RE
93f7a1d
+    qr/\(?{/
93f7a1d
+CODE
93f7a1d
+    qr/Constant\(qq\) unknown/,
93f7a1d
+    { stderr => 1 },
93f7a1d
+    'qr/\(?{';
93f7a1d
-- 
93f7a1d
2.20.1
93f7a1d