From ad5fedb002a4e7befcb1bd42bd788878f37a0d6e Mon Sep 17 00:00:00 2001 From: David Mitchell Date: Tue, 15 Nov 2022 19:31:14 +0000 Subject: for loops: protect GV/LVREF from premature free In something like for $package_var (....) { ... } or more experimentally, for \$lvref (....) { ... } when entering the loop in pp_enteriter, perl would pop the GV/LVREF off the stack, but didn't bump its refcount. Thus it was possible (if unlikely) that it could be freed during the loop. In particular this crashed: $f = "foo"; for ${*$f} (1,2) { delete $main::{$f}; # delete the glob *foo ...; } This will become more serious when the stack becomes refcounted, as popping something off the stack will trigger a refcount decrement on it and thus a possible immediate free of the GV. This commit future-proofs for loops against this by ensuring that the refcount of the SV referred to by cx->blk_loop.itervar_u.svp is appropriately bumped up / down on entering / exiting the loop. --- pp_ctl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'pp_ctl.c') diff --git a/pp_ctl.c b/pp_ctl.c index b16afcebcd..2a5d6ba1d2 100644 --- a/pp_ctl.c +++ b/pp_ctl.c @@ -2282,6 +2282,7 @@ PP(pp_enteriter) SV * const sv = POPs; itervarp = (void *)sv; if (LIKELY(isGV(sv))) { /* symbol table variable */ + SvREFCNT_inc_simple_void(sv); itersave = GvSV(sv); SvREFCNT_inc_simple_void(itersave); cxflags = CXp_FOR_GV; @@ -2294,6 +2295,7 @@ PP(pp_enteriter) assert(SvMAGIC(sv)->mg_type == PERL_MAGIC_lvref); itersave = NULL; cxflags = CXp_FOR_LVREF; + SvREFCNT_inc_simple_void(sv); } } /* OPpITER_DEF (implicit $_) should only occur with a GV iter var */ -- cgit v1.2.1