summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2022-11-15 19:31:14 +0000
committerYves Orton <demerphq@gmail.com>2023-02-28 20:53:51 +0800
commitad5fedb002a4e7befcb1bd42bd788878f37a0d6e (patch)
treef5f4698d0773ca1556749001038e125249a86202 /t
parent7460e4ea20e79a71632e499d2af24ad90ee1c58e (diff)
downloadperl-ad5fedb002a4e7befcb1bd42bd788878f37a0d6e.tar.gz
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.
Diffstat (limited to 't')
-rw-r--r--t/op/for.t16
1 files changed, 16 insertions, 0 deletions
diff --git a/t/op/for.t b/t/op/for.t
index a4d80664d8..b931a66a6c 100644
--- a/t/op/for.t
+++ b/t/op/for.t
@@ -756,4 +756,20 @@ is(fscope(), 1, 'return via loop in sub');
}
}
+# the GV of the loop variable didn't have its refcount bumped while being
+# used by the loop, so it was possible to free it mid-loop. This used to
+# assert/SEGV
+
+{
+ my $f = "a_low_refcnt_package_var";
+ my $i = 0;
+ no strict 'refs';
+ for ${*$f} (5,11,33) {
+ delete $main::{$f};
+ $i++;
+ }
+ is($i, 3, "deleting glob is safe");
+}
+
+
done_testing();