Subject: | dead lexicals make for segfaults |
If a lexical has been freed but it's in the pad list, PadWalker still tries to
make a reference to it (but it's been nulled, onoes!). Boom, segfault (at the
very least on perl 5.10, haven't tested in others).
Attached patch fixes the problem and adds a test for it.
Here's a one-liner to reproduce the segfault, courtesy of rafl++:
perl -MPadWalker=peek_my -e'my $x = 42; sub { my $closed_over = $x;
sub { peek_my 0 } }->()->()'
Subject: | dead_lexicals.patch |
commit 9aa82bc9912eac3de18a64421c4eac9b17865e40
Author: Paul Driver <frodwith@gmail.com>
Date: Thu Mar 4 17:46:55 2010 -0800
fixed bug with dead lexicals causing a segfault
diff --git a/PadWalker.xs b/PadWalker.xs
index 4048257..a8f5384 100644
--- a/PadWalker.xs
+++ b/PadWalker.xs
@@ -232,10 +232,6 @@ pads_into_hash(AV* pad_namelist, AV* pad_vallist, HV* my_hash, HV* our_hash, U32
else {
if (is_our) {
val_sv = fetch_from_stash(SvOURSTASH(name_sv), name_str, name_len);
- if (!val_sv) {
- debug_print(("Value of our variable is undefined\n"));
- val_sv = &PL_sv_undef;
- }
}
else
{
@@ -243,6 +239,12 @@ pads_into_hash(AV* pad_namelist, AV* pad_vallist, HV* my_hash, HV* our_hash, U32
val_sv = val_ptr ? *val_ptr : &PL_sv_undef;
}
+ if (!val_sv) {
+ debug_print(("Value of %s variable is undefined\n",
+ is_our ? "our" : "my"));
+ val_sv = &PL_sv_undef;
+ }
+
hv_store((is_our ? our_hash : my_hash), name_str, name_len,
newRV_inc(val_sv), 0);
}
diff --git a/t/dead_my.t b/t/dead_my.t
new file mode 100644
index 0000000..8812938
--- /dev/null
+++ b/t/dead_my.t
@@ -0,0 +1,11 @@
+use PadWalker qw(peek_my);
+
+print "1..1\n";
+
+my $outer = 42;
+sub {
+ my $inner = $outer;
+ sub { peek_my 0 }
+}->()->();
+
+print "ok 1\n";