diff --git a/inline.h b/inline.h index 863cbb8601f6..6ade3af4ca8b 100644 --- a/inline.h +++ b/inline.h @@ -4152,6 +4152,25 @@ Perl_cx_poploop(pTHX_ PERL_CONTEXT *cx) cx->blk_loop.itersave = NULL; SvREFCNT_dec(cursv); } + if (CxPADLOOP(cx)) { + /* for my ... might be multivariable. my_op->op_next will point at + * the OP_ITER whose op_targ contains the count of how many more + * variables + */ + OP *iterop = cx->blk_loop.my_op->op_next; + assert(iterop->op_type == OP_ITER); + PADOFFSET how_many = iterop->op_targ; + /* op_targ actually stores count - 1, so it's the count of additional + * vars after itervar itself */ + for (SV **svp = cx->blk_loop.itervar_u.svp + 1; how_many; svp++, how_many--) { + /* we didn't store an itersave for these, but we know they are all + * scoped to the loop we have just left. It's therefore safe to store + * &PL_sv_undef there since they weren't live before or afterwards. + */ + SvREFCNT_dec(*svp); + *svp = &PL_sv_undef; + } + } if (cx->cx_type & CXp_FOR_LVREF) { SV *itervar = (SV *)(cx)->blk_loop.itervar_u.gv; SV *origval = (cx)->blk_loop.itersave; diff --git a/t/op/for-many.t b/t/op/for-many.t index 035d1da07e91..f36df50f7ff9 100644 --- a/t/op/for-many.t +++ b/t/op/for-many.t @@ -511,4 +511,19 @@ is($continue, 'xx', 'continue reached twice'); pass '2-var for does not crash on lexical sub calls'; } +# all foreach iteration vars are cleared in a timely manner +{ + my @arrx; + my @arry; + + for my ($x, $y) (\@arrx, \@arry) { + # list items are aliased; add 1 to account for \ ref in the following + refcount_is \@arrx, 2+1, 'arrx refcount 2 inside loop'; + refcount_is \@arry, 2+1, 'arry refcount 2 inside loop'; + } + + refcount_is \@arrx, 1+1, 'arrx refcount 1 after loop'; + refcount_is \@arry, 1+1, 'arry refcount 1 after loop'; +} + done_testing();