Skip to content

Commit 01c852d

Browse files
committed
fix panic from eval {} inside /(?{...})/
GH #19680 Normally in code like eval {.... }; then even if the eval is the last statement in the file or sub, the OP_LEAVETRY isn't the last op in the execution path: it's followed by an OP_LEAVE or OP_LEAVESUB or whatever, which will be the op to resume execution from after an exception is caught. However, if the eval is the *last* thing within a regex code block: /(?{ ...; eval {....}; })/ then the op_next pointer of the OP_LEAVETRY op is actually NULL. This confused S_docatch(), which wrongly assumed that a NULL PL_restartop indicated that the caught exception should be rethrown, popping execution back to the outer perl_run() call and hence leading to the confused panic warning: "panic: restartop in perl_run" The fix is to to separate out the "do we need to re-throw" test, (PL_restartjmpenv != PL_top_env), from the "no more ops so no need to re-enter the runops loop" test, (!PL_restartop).
1 parent 97039a4 commit 01c852d

File tree

2 files changed

+15
-3
lines changed

2 files changed

+15
-3
lines changed

pp_ctl.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3350,8 +3350,11 @@ S_docatch(pTHX_ Perl_ppaddr_t firstpp)
33503350
CALLRUNOPS(aTHX);
33513351
break;
33523352
case 3:
3353-
/* die caught by an inner eval - continue inner loop */
3354-
if (PL_restartop && PL_restartjmpenv == PL_top_env) {
3353+
if (PL_restartjmpenv == PL_top_env) {
3354+
/* die caught by an inner eval - continue inner loop */
3355+
3356+
if (!PL_restartop)
3357+
break;
33553358
PL_restartjmpenv = NULL;
33563359
PL_op = PL_restartop;
33573360
PL_restartop = 0;

t/re/pat_re_eval.t

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ BEGIN {
2424

2525
our @global;
2626

27-
plan tests => 506; # Update this when adding/deleting tests.
27+
plan tests => 507; # Update this when adding/deleting tests.
2828

2929
run_tests() unless caller;
3030

@@ -1332,6 +1332,15 @@ sub run_tests {
13321332
pass("SvTEMP 2");
13331333
}
13341334

1335+
# GH #19680 "panic: restartop in perl_run"
1336+
# The eval block embedded within the (?{}) - but with no more code
1337+
# following it - causes the next op after the OP_LEAVETRY to be NULL
1338+
# (not even an OP_LEAVE). This confused the exception-catching and
1339+
# rethrowing code: it was incorrectly rethrowing the exception rather
1340+
# than just stopping at that point.
1341+
1342+
ok("test" =~ m{^ (?{eval {die "boo!"}}) test $}x, "GH #19680");
1343+
13351344
} # End of sub run_tests
13361345

13371346
1;

0 commit comments

Comments
 (0)