diff options
author | Dave Mitchell <davem@fdisolutions.com> | 2005-05-02 14:27:20 +0000 |
---|---|---|
committer | Dave Mitchell <davem@fdisolutions.com> | 2005-05-02 14:27:20 +0000 |
commit | abd70938721b65db3288384c514cb47b77a12268 (patch) | |
tree | dc402b0f8ccfbe6e2a305887f31c59548d7601f3 /pp_ctl.c | |
parent | 745cf2ffbef88177c764dae7c27dbc293c1abb81 (diff) | |
download | perl-abd70938721b65db3288384c514cb47b77a12268.tar.gz |
Better fix for #8738 (Core dump in 'leavetry')
When in an inner runops loop (eg via a tie or sort), an eval
needs a new JMPENV pushing by S_docatch. If an exception is raised,
control is returned to S_docatch, and it must determine whether
the eval that trapped the exception is an inner eval or an outer
one. In the former case, restart the loop, in the latter case,
rethrow the exception. This is determined by whether we are still
at the same PL_curstackinfo level. This fails in the case of
SPLICE(), which pushes a new SETJMP and runops level, but not a
new stackinfo level. There may be other code which does similar.
The solution is to store the current value of PL_top_env in each
pushed CxEVAL, and see if it's still the same as PL_top_env when
the exception is handled.
p4raw-id: //depot/perl@24363
Diffstat (limited to 'pp_ctl.c')
-rw-r--r-- | pp_ctl.c | 16 |
1 files changed, 14 insertions, 2 deletions
@@ -2681,7 +2681,6 @@ S_docatch(pTHX_ OP *o) { int ret; OP * const oldop = PL_op; - volatile PERL_SI *cursi = PL_curstackinfo; dJMPENV; #ifdef DEBUGGING @@ -2692,12 +2691,25 @@ S_docatch(pTHX_ OP *o) JMPENV_PUSH(ret); switch (ret) { case 0: + assert(cxstack_ix >= 0); + assert(CxTYPE(&cxstack[cxstack_ix]) == CXt_EVAL); + cxstack[cxstack_ix].blk_eval.cur_top_env = PL_top_env; redo_body: docatch_body(); break; case 3: /* die caught by an inner eval - continue inner loop */ - if (PL_restartop && cursi == PL_curstackinfo) { + + /* NB XXX we rely on the old popped CxEVAL still being at the top + * of the stack; the way die_where() currently works, this + * assumption is valid. In theory The cur_top_env value should be + * returned in another global, the way retop (aka PL_restartop) + * is. */ + assert(CxTYPE(&cxstack[cxstack_ix+1]) == CXt_EVAL); + + if (PL_restartop + && cxstack[cxstack_ix+1].blk_eval.cur_top_env == PL_top_env) + { PL_op = PL_restartop; PL_restartop = 0; goto redo_body; |