diff options
author | Dave Mitchell <davem@fdisolutions.com> | 2002-12-10 01:26:44 +0000 |
---|---|---|
committer | Rafael Garcia-Suarez <rgarciasuarez@gmail.com> | 2002-12-14 22:34:25 +0000 |
commit | 7dafbf5232bace07a044625a5a956b73da3928d5 (patch) | |
tree | 5042129d851b4706c4c22a7c67de6b3092bc08cb /pod/perlintern.pod | |
parent | 0412d5267fa2300f66eb4eb554e2af493b5e5b33 (diff) | |
download | perl-7dafbf5232bace07a044625a5a956b73da3928d5.tar.gz |
Proper fix for CvOUTSIDE weak refcounting
Message-ID: <20021210012644.A7843@fdgroup.com>
p4raw-id: //depot/perl@18302
Diffstat (limited to 'pod/perlintern.pod')
-rw-r--r-- | pod/perlintern.pod | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/pod/perlintern.pod b/pod/perlintern.pod index ea5c902c0f..c2e246a8d9 100644 --- a/pod/perlintern.pod +++ b/pod/perlintern.pod @@ -11,6 +11,67 @@ format but are not marked as part of the Perl API. In other words, B<they are not for use in extensions>! +=head1 CV reference counts and CvOUTSIDE + +=over 8 + +=item CvWEAKOUTSIDE + +Each CV has a pointer, C<CvOUTSIDE()>, to its lexically enclosing +CV (if any). Because pointers to anonymous sub prototypes are +stored in C<&> pad slots, it is a possible to get a circular reference, +with the parent pointing to the child and vice-versa. To avoid the +ensuing memory leak, we do not increment the reference count of the CV +pointed to by C<CvOUTSIDE> in the I<one specific instance> that the parent +has a C<&> pad slot pointing back to us. In this case, we set the +C<CvWEAKOUTSIDE> flag in the child. This allows us to determine under what +circumstances we should decrement the refcount of the parent when freeing +the child. + +There is a further complication with non-closure anonymous subs (ie those +that do not refer to any lexicals outside that sub). In this case, the +anonymous prototype is shared rather than being cloned. This has the +consequence that the parent may be freed while there are still active +children, eg + + BEGIN { $a = sub { eval '$x' } } + +In this case, the BEGIN is freed immediately after execution since there +are no active references to it: the anon sub prototype has +C<CvWEAKOUTSIDE> set since it's not a closure, and $a points to the same +CV, so it doesn't contribute to BEGIN's refcount either. When $a is +executed, the C<eval '$x'> causes the chain of C<CvOUTSIDE>s to be followed, +and the freed BEGIN is accessed. + +To avoid this, whenever a CV and its associated pad is freed, any +C<&> entries in the pad are explicitly removed from the pad, and if the +refcount of the pointed-to anon sub is still positive, then that +child's C<CvOUTSIDE> is set to point to its grandparent. This will only +occur in the single specific case of a non-closure anon prototype +having one or more active references (such as C<$a> above). + +One other thing to consider is that a CV may be merely undefined +rather than freed, eg C<undef &foo>. In this case, its refcount may +not have reached zero, but we still delete its pad and its C<CvROOT> etc. +Since various children may still have their C<CvOUTSIDE> pointing at this +undefined CV, we keep its own C<CvOUTSIDE> for the time being, so that +the chain of lexical scopes is unbroken. For example, the following +should print 123: + + my $x = 123; + sub tmp { sub { eval '$x' } } + my $a = tmp(); + undef &tmp; + print $a->(); + + bool CvWEAKOUTSIDE(CV *cv) + +=for hackers +Found in file cv.h + + +=back + =head1 Functions in file pad.h @@ -550,7 +611,8 @@ Found in file pad.c =item pad_fixup_inner_anons For any anon CVs in the pad, change CvOUTSIDE of that CV from -old_cv to new_cv if necessary. +old_cv to new_cv if necessary. Needed when a newly-compiled CV has to be +moved to a pre-existing CV struct. void pad_fixup_inner_anons(PADLIST *padlist, CV *old_cv, CV *new_cv) @@ -651,6 +713,9 @@ PL_*pad* global vars so that we don't have any dangling references left. We also repoint the CvOUTSIDE of any about-to-be-orphaned inner subs to the outer of this cv. +(This function should really be called pad_free, but the name was already +taken) + void pad_undef(CV* cv) =for hackers |