In perl.git, the branch davem/post-5.12 has been updated

<http://perl5.git.perl.org/perl.git/commitdiff/27e904532594b7fb224bdf9a05bf3b5336b8a39e?hp=1c98cc53150c48606faf09909b3bb3a4ebdd329f>

- Log -----------------------------------------------------------------
commit 27e904532594b7fb224bdf9a05bf3b5336b8a39e
Author: David Mitchell <da...@iabyn.com>
Date:   Thu Apr 8 13:16:56 2010 +0100

    fix RT 23810: eval and tied methods
    
    Something like the following ended up corrupted:
        sub FETCH { eval 'BEGIN{syntax err}' }
    The croak on error popped back the context stack etc to the EVAL pushed by
    entereval, but the corresponding JUMPENV_PUSH(3) unwound all the way to the
    outer perl_run, losing all the mg_get() related parts of the C stack.
    
    It turns out that the run-time parts of pp_entereval were protected with
    a new JUMPENV level, but the compile-time parts weren't. Add this.

M       pp_ctl.c
M       t/op/tie.t

commit 91e35ba127b7082418836f7f9f428e4d2f9b5745
Author: David Mitchell <da...@iabyn.com>
Date:   Tue Apr 6 20:53:45 2010 +0100

    more mods to -Dl debugging output

M       cop.h
-----------------------------------------------------------------------

Summary of changes:
 cop.h      |   15 ++++------
 pp_ctl.c   |   72 ++++++++++++++++++++++++++++++++++++++++--------
 t/op/tie.t |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 156 insertions(+), 21 deletions(-)

diff --git a/cop.h b/cop.h
index 2d0a459..6c51d73 100644
--- a/cop.h
+++ b/cop.h
@@ -103,9 +103,8 @@ typedef struct jmpenv JMPENV;
        DEBUG_l({                                                       \
            int i = 0; JMPENV *p = PL_top_env;                          \
            while (p) { i++; p = p->je_prev; }                          \
-           Perl_deb(aTHX_ "push JUMPLEVEL %d (now %p, was %p) at %s:%d\n",\
-                        i, (void*)&cur_env, (void*)PL_top_env,         \
-                        __FILE__, __LINE__);})                         \
+           Perl_deb(aTHX_ "JUMPENV_PUSH level=%d at %s:%d\n",          \
+                        i,  __FILE__, __LINE__);})                     \
        cur_env.je_prev = PL_top_env;                                   \
        OP_REG_TO_MEM;                                                  \
        cur_env.je_ret = PerlProc_setjmp(cur_env.je_buf, 
SCOPE_SAVES_SIGNAL_MASK);              \
@@ -120,9 +119,8 @@ typedef struct jmpenv JMPENV;
        DEBUG_l({                                                       \
            int i = -1; JMPENV *p = PL_top_env;                         \
            while (p) { i++; p = p->je_prev; }                          \
-           Perl_deb(aTHX_ "pop  JUMPLEVEL %d (now %p, was %p) at %s:%d\n",\
-                        i, (void*)cur_env.je_prev, (void*)PL_top_env,  \
-                        __FILE__, __LINE__);})                         \
+           Perl_deb(aTHX_ "JUMPENV_POP level=%d at %s:%d\n",           \
+                        i, __FILE__, __LINE__);})                      \
        assert(PL_top_env == &cur_env);                                 \
        PL_top_env = cur_env.je_prev;                                   \
     } STMT_END
@@ -132,9 +130,8 @@ typedef struct jmpenv JMPENV;
        DEBUG_l({                                               \
            int i = -1; JMPENV *p = PL_top_env;                 \
            while (p) { i++; p = p->je_prev; }                  \
-           Perl_deb(aTHX_ "JUMP JUMPLEVEL %d (%p) at %s:%d\n", \
-                        i, (void*)PL_top_env,                  \
-                        __FILE__, __LINE__);})                 \
+           Perl_deb(aTHX_ "JUMPENV_JUMP(%d) level=%d at %s:%d\n", \
+                        (int)v, i, __FILE__, __LINE__);})      \
        OP_REG_TO_MEM;                                          \
        if (PL_top_env->je_prev)                                \
            PerlProc_longjmp(PL_top_env->je_buf, (v));          \
diff --git a/pp_ctl.c b/pp_ctl.c
index 80c7b22..bbb2d15 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -1653,6 +1653,10 @@ Perl_die_where(pTHX_ SV *msv)
                SV * const nsv = cx->blk_eval.old_namesv;
                 (void)hv_store(GvHVn(PL_incgv), SvPVX_const(nsv), SvCUR(nsv),
                                &PL_sv_undef, 0);
+               /* note that unlike pp_entereval, pp_require isn't
+                * supposed to trap errors. So now that we've popped the
+                * EVAL that pp_require pushed, and processed the error
+                * message, rethrow the error */
                DIE(aTHX_ "%sCompilation failed in require",
                    *msg ? msg : "Unknown error\n");
            }
@@ -3041,6 +3045,35 @@ Perl_find_runcv(pTHX_ U32 *db_seqp)
 }
 
 
+/* Run yyparse() in a setjmp wrapper. Returns:
+ *   0: yyparse() successful
+ *   1: yyparse() failed
+ *   3: yyparse() died
+ */
+STATIC int
+S_try_yyparse(pTHX)
+{
+    int ret;
+    dJMPENV;
+
+    assert(CxTYPE(&cxstack[cxstack_ix]) == CXt_EVAL);
+    JMPENV_PUSH(ret);
+    switch (ret) {
+    case 0:
+       ret = yyparse() ? 1 : 0;
+       break;
+    case 3:
+       break;
+    default:
+       JMPENV_POP;
+       JMPENV_JUMP(ret);
+       /* NOTREACHED */
+    }
+    JMPENV_POP;
+    return ret;
+}
+
+
 /* Compile a require/do, an eval '', or a /(?{...})/.
  * In the last case, startop is non-null, and contains the address of
  * a pointer that should be set to the just-compiled code.
@@ -3055,8 +3088,10 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, U32 
seq)
 {
     dVAR; dSP;
     OP * const saveop = PL_op;
+    bool in_require = (saveop && saveop->op_type == OP_REQUIRE);
+    int yystatus;
 
-    PL_in_eval = ((saveop && saveop->op_type == OP_REQUIRE)
+    PL_in_eval = (in_require
                  ? (EVAL_INREQUIRE | (PL_in_eval & EVAL_INEVAL))
                  : EVAL_INEVAL);
 
@@ -3108,27 +3143,39 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, 
U32 seq)
        PL_in_eval |= EVAL_KEEPERR;
     else
        CLEAR_ERRSV();
-    if (yyparse() || PL_parser->error_count || !PL_eval_root) {
+
+    /* note that yyparse() may raise an exception, e.g. C<BEGIN{die}>,
+     * so honour CATCH_GET and trap it here if necessary */
+
+    yystatus = (!in_require && CATCH_GET) ? S_try_yyparse(aTHX) : yyparse();
+
+    if (yystatus || PL_parser->error_count || !PL_eval_root) {
        SV **newsp;                     /* Used by POPBLOCK. */
        PERL_CONTEXT *cx = &cxstack[cxstack_ix];
-       I32 optype = 0;                 /* Might be reset by POPEVAL. */
+       I32 optype;                     /* Used by POPEVAL. */
        const char *msg;
 
+       PERL_UNUSED_VAR(newsp);
+       PERL_UNUSED_VAR(optype);
+
        PL_op = saveop;
        if (PL_eval_root) {
            op_free(PL_eval_root);
            PL_eval_root = NULL;
        }
-       SP = PL_stack_base + POPMARK;           /* pop original mark */
-       if (!startop) {
-           POPBLOCK(cx,PL_curpm);
-           POPEVAL(cx);
+       if (yystatus != 3) {
+           SP = PL_stack_base + POPMARK;       /* pop original mark */
+           if (!startop) {
+               POPBLOCK(cx,PL_curpm);
+               POPEVAL(cx);
+           }
        }
        lex_end();
-       LEAVE_with_name("eval"); /* pp_entereval knows about this LEAVE.  */
+       if (yystatus != 3)
+           LEAVE_with_name("eval"); /* pp_entereval knows about this LEAVE.  */
 
        msg = SvPVx_nolen_const(ERRSV);
-       if (optype == OP_REQUIRE) {
+       if (in_require) {
            const SV * const nsv = cx->blk_eval.old_namesv;
            (void)hv_store(GvHVn(PL_incgv), SvPVX_const(nsv), SvCUR(nsv),
                           &PL_sv_undef, 0);
@@ -3136,8 +3183,10 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, U32 
seq)
                       *msg ? msg : "Unknown error\n");
        }
        else if (startop) {
-           POPBLOCK(cx,PL_curpm);
-           POPEVAL(cx);
+           if (yystatus != 3) {
+               POPBLOCK(cx,PL_curpm);
+               POPEVAL(cx);
+           }
            Perl_croak(aTHX_ "%sCompilation failed in regexp",
                       (*msg ? msg : "Unknown error\n"));
        }
@@ -3146,7 +3195,6 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, U32 
seq)
                sv_setpvs(ERRSV, "Compilation error");
            }
        }
-       PERL_UNUSED_VAR(newsp);
        PUSHs(&PL_sv_undef);
        PUTBACK;
        return FALSE;
diff --git a/t/op/tie.t b/t/op/tie.t
index a2e1d4a..0ec8050 100644
--- a/t/op/tie.t
+++ b/t/op/tie.t
@@ -658,3 +658,93 @@ sub STORE {
 tie $SELECT, 'main';
 $SELECT = *STDERR;
 EXPECT
+########
+# RT 23810: eval in die in FETCH can corrupt context stack
+
+my $file = 'rt23810.pm';
+
+my $e;
+my $s;
+
+sub do_require {
+    my ($str, $eval) = @_;
+    open my $fh, '>', $file or die "Can't create $file: $!\n";
+    print $fh $str;
+    close $fh;
+    if ($eval) {
+       $s .= '-ERQ';
+       eval { require $pm; $s .= '-ENDE' }
+    }
+    else {
+       $s .= '-RQ';
+       require $pm;
+    }
+    $s .= '-ENDRQ';
+    unlink $file;
+}
+
+sub TIEHASH { bless {} }
+
+sub FETCH {
+    # 10 or more syntax errors makes yyparse croak()
+    my $bad = q{$x+;$x+;$x+;$x+;$x+;$x+;$x+;$x+;$x+$x+;$x+;$x+;$x+;$x+;;$x+;};
+
+    if ($_[1] eq 'eval') {
+       $s .= 'EVAL';
+       eval q[BEGIN { die; $s .= '-X1' }];
+       $s .= '-BD';
+       eval q[BEGIN { $x+ }];
+       $s .= '-BS';
+       eval '$x+';
+       $s .= '-E1';
+       $s .= '-S1' while $@ =~ /syntax error at/g;
+       eval $bad;
+       $s .= '-E2';
+       $s .= '-S2' while $@ =~ /syntax error at/g;
+    }
+    elsif ($_[1] eq 'require') {
+       $s .= 'REQUIRE';
+       my @text = (
+           q[BEGIN { die; $s .= '-X1' }],
+           q[BEGIN { $x+ }],
+           '$x+',
+           $bad
+       );
+       for my $i (0..$#text) {
+           $s .= "-$i";
+           do_require($txt[$i], 0) if $e;;
+           do_require($txt[$i], 1);
+       }
+    }
+    elsif ($_[1] eq 'exit') {
+       eval q[exit(0); print "overshot eval\n"];
+    }
+    else {
+       print "unknown key: '$_[1]'\n";
+    }
+    return "-R";
+}
+my %foo;
+tie %foo, "main";
+
+for my $action(qw(eval require)) {
+    $s = ''; $e = 0; $s .= main->FETCH($action); print "$action: s0=$s\n";
+    $s = ''; $e = 1; eval { $s .= main->FETCH($action)}; print "$action: 
s1=$s\n";
+    $s = ''; $e = 0; $s .= $foo{$action}; print "$action: s2=$s\n";
+    $s = ''; $e = 1; eval { $s .= $foo{$action}}; print "$action: s3=$s\n";
+}
+1 while unlink $file;
+
+$foo{'exit'};
+print "overshot main\n"; # shouldn't reach here
+
+EXPECT
+eval: s0=EVAL-BD-BS-E1-S1-E2-S2-S2-S2-S2-S2-S2-S2-S2-S2-S2-R
+eval: s1=EVAL-BD-BS-E1-S1-E2-S2-S2-S2-S2-S2-S2-S2-S2-S2-S2-R
+eval: s2=EVAL-BD-BS-E1-S1-E2-S2-S2-S2-S2-S2-S2-S2-S2-S2-S2-R
+eval: s3=EVAL-BD-BS-E1-S1-E2-S2-S2-S2-S2-S2-S2-S2-S2-S2-S2-R
+require: s0=REQUIRE-0-ERQ-ENDRQ-1-ERQ-ENDRQ-2-ERQ-ENDRQ-3-ERQ-ENDRQ-R
+require: s1=REQUIRE-0-RQ
+require: s2=REQUIRE-0-ERQ-ENDRQ-1-ERQ-ENDRQ-2-ERQ-ENDRQ-3-ERQ-ENDRQ-R
+require: s3=REQUIRE-0-RQ
+

--
Perl5 Master Repository

Reply via email to