3d76a21
From 35ad0133df9b65a4e32f2f07a2a05b387bd79591 Mon Sep 17 00:00:00 2001
3d76a21
From: Tony Cook <tony@develop-help.com>
3d76a21
Date: Thu, 3 Jan 2019 10:48:05 +1100
3d76a21
Subject: [PATCH] (perl #133575) prevent set/longjmp clobbering locals in
3d76a21
 S_fold_constants
3d76a21
MIME-Version: 1.0
3d76a21
Content-Type: text/plain; charset=UTF-8
3d76a21
Content-Transfer-Encoding: 8bit
3d76a21
3d76a21
My original approach moved the whole switch into the new function,
3d76a21
but that was a lot messier, and I don't think it's necessary.
3d76a21
3d76a21
pad_swipe() can throw, but only for panics, and in DESTROY if
3d76a21
refadjust is true, which isn't the case here.
3d76a21
3d76a21
CLEAR_ERRSV() might throw if the code called by CALLRUNOPS()
3d76a21
puts an object that dies in DESTROY in $@, but I think that
3d76a21
might cause an infinite loop in the original code.
3d76a21
3d76a21
Signed-off-by: Petr Písař <ppisar@redhat.com>
3d76a21
---
3d76a21
 op.c | 32 ++++++++++++++++++++++++--------
3d76a21
 1 file changed, 24 insertions(+), 8 deletions(-)
3d76a21
3d76a21
diff --git a/op.c b/op.c
3d76a21
index 146407ba70..0b46b348cb 100644
3d76a21
--- a/op.c
3d76a21
+++ b/op.c
3d76a21
@@ -5464,15 +5464,34 @@ S_op_integerize(pTHX_ OP *o)
3d76a21
     return o;
3d76a21
 }
3d76a21
 
3d76a21
+/* This function exists solely to provide a scope to limit
3d76a21
+   setjmp/longjmp() messing with auto variables.
3d76a21
+ */
3d76a21
+PERL_STATIC_INLINE int
3d76a21
+S_fold_constants_eval(pTHX) {
3d76a21
+    int ret = 0;
3d76a21
+    dJMPENV;
3d76a21
+
3d76a21
+    JMPENV_PUSH(ret);
3d76a21
+
3d76a21
+    if (ret == 0) {
3d76a21
+	CALLRUNOPS(aTHX);
3d76a21
+    }
3d76a21
+
3d76a21
+    JMPENV_POP;
3d76a21
+
3d76a21
+    return ret;
3d76a21
+}
3d76a21
+
3d76a21
 static OP *
3d76a21
 S_fold_constants(pTHX_ OP *const o)
3d76a21
 {
3d76a21
     dVAR;
3d76a21
-    OP * volatile curop;
3d76a21
+    OP *curop;
3d76a21
     OP *newop;
3d76a21
-    volatile I32 type = o->op_type;
3d76a21
+    I32 type = o->op_type;
3d76a21
     bool is_stringify;
3d76a21
-    SV * volatile sv = NULL;
3d76a21
+    SV *sv = NULL;
3d76a21
     int ret = 0;
3d76a21
     OP *old_next;
3d76a21
     SV * const oldwarnhook = PL_warnhook;
3d76a21
@@ -5480,7 +5499,6 @@ S_fold_constants(pTHX_ OP *const o)
3d76a21
     COP not_compiling;
3d76a21
     U8 oldwarn = PL_dowarn;
3d76a21
     I32 old_cxix;
3d76a21
-    dJMPENV;
3d76a21
 
3d76a21
     PERL_ARGS_ASSERT_FOLD_CONSTANTS;
3d76a21
 
3d76a21
@@ -5582,15 +5600,15 @@ S_fold_constants(pTHX_ OP *const o)
3d76a21
     assert(IN_PERL_RUNTIME);
3d76a21
     PL_warnhook = PERL_WARNHOOK_FATAL;
3d76a21
     PL_diehook  = NULL;
3d76a21
-    JMPENV_PUSH(ret);
3d76a21
 
3d76a21
     /* Effective $^W=1.  */
3d76a21
     if ( ! (PL_dowarn & G_WARN_ALL_MASK))
3d76a21
 	PL_dowarn |= G_WARN_ON;
3d76a21
 
3d76a21
+    ret = S_fold_constants_eval(aTHX);
3d76a21
+
3d76a21
     switch (ret) {
3d76a21
     case 0:
3d76a21
-	CALLRUNOPS(aTHX);
3d76a21
 	sv = *(PL_stack_sp--);
3d76a21
 	if (o->op_targ && sv == PAD_SV(o->op_targ)) {	/* grab pad temp? */
3d76a21
 	    pad_swipe(o->op_targ,  FALSE);
3d76a21
@@ -5608,7 +5626,6 @@ S_fold_constants(pTHX_ OP *const o)
3d76a21
 	o->op_next = old_next;
3d76a21
 	break;
3d76a21
     default:
3d76a21
-	JMPENV_POP;
3d76a21
 	/* Don't expect 1 (setjmp failed) or 2 (something called my_exit)  */
3d76a21
 	PL_warnhook = oldwarnhook;
3d76a21
 	PL_diehook  = olddiehook;
3d76a21
@@ -5616,7 +5633,6 @@ S_fold_constants(pTHX_ OP *const o)
3d76a21
 	 * the stack - eg any nested evals */
3d76a21
 	Perl_croak(aTHX_ "panic: fold_constants JMPENV_PUSH returned %d", ret);
3d76a21
     }
3d76a21
-    JMPENV_POP;
3d76a21
     PL_dowarn   = oldwarn;
3d76a21
     PL_warnhook = oldwarnhook;
3d76a21
     PL_diehook  = olddiehook;
3d76a21
-- 
3d76a21
2.17.2
3d76a21