summaryrefslogtreecommitdiff
path: root/pad.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2012-09-03 21:26:37 -0700
committerFather Chrysostomos <sprout@cpan.org>2012-09-15 22:45:07 -0700
commit1f122f9b83a0a767aa3a264b32482be38722715d (patch)
tree66e91e46cb294c3d0b7b8f7311c43fcb28e09d12 /pad.c
parent8d88fe29d7f8e580970ac5a994ba499606884c4c (diff)
downloadperl-1f122f9b83a0a767aa3a264b32482be38722715d.tar.gz
CvOUTSIDE should be strong for lexsub declared in inner pack sub
PadnameOUTER (SvFAKE) entries in pads of clonable subs contain the offset in the parent pad where the closed-over entry is to be found. The pad itself does not reference the outer lexical until the sub is cloned at run time. newMYSUB had to account for that by following CvOUTSIDE for PadnameOUTER entries, to account for cases like this: my sub foo; my sub bar { sub foo {} } The sub foo{} definition would have to find the my sub foo declaration from outside and store the sub there. That code was not accounting for named package subs, which close over variables at compile time, so they don’t need (and don’t) store a par- ent offset. So outcv would point to bar in this case: my sub foo; sub bar { sub foo {} } If outcv matched CvOUTSIDE(foo), then CvOUTSIDE was made weak. That does not help in cases like this: undef *bar; { my sub foo; sub bar { sub foo {} } } If foo has a weak CvOUTSIDE pointer, then it will still point to bar after bar is freed, which does not help when the sub is cloned and tries to look at CvROOT(CvOUTSIDE). If the pad name is marked PadnameOUTER, even if it has no parent pad index, newMYSUB needs to leave the CvOUTSIDE pointer strongc. Also, pad_fixup_inner_anons did not account for subs with strong CvOUTSIDE pointers whose CvOUTSIDE point to the sub whose pad is being iterated through.
Diffstat (limited to 'pad.c')
-rw-r--r--pad.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/pad.c b/pad.c
index 29ad4ad8dd..f6c47f5bbd 100644
--- a/pad.c
+++ b/pad.c
@@ -2218,7 +2218,10 @@ Perl_pad_fixup_inner_anons(pTHX_ PADLIST *padlist, CV *old_cv, CV *new_cv)
: NULL;
CV * const innercv = MUTABLE_CV(mg ? mg->mg_obj : curpad[ix]);
if (CvOUTSIDE(innercv) == old_cv) {
- assert(CvWEAKOUTSIDE(innercv));
+ if (!CvWEAKOUTSIDE(innercv)) {
+ SvREFCNT_dec(old_cv);
+ SvREFCNT_inc_simple_void_NN(new_cv);
+ }
CvOUTSIDE(innercv) = new_cv;
}
}