This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Weak refs to pad hvs should go stale
authorFather Chrysostomos <sprout@cpan.org>
Sat, 5 Nov 2011 20:26:41 +0000 (13:26 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sat, 5 Nov 2011 20:26:41 +0000 (13:26 -0700)
When a lexical variable goes out of scope, as in

    {
        my %lexical_variable;
        ...
    }
    # no longer in scope here

it is supposed to disappear as far as Perl code can tell.  That the
same SV is reused the next time that scope is entered is an implement-
ation detail.

The move of hashes’ back-references from magic into the HvAUX struc-
ture in 5.10 caused this implementation detail to leak through.

Normally, weak references to pad variables going out of scope are
killed off:

    {
        my $scalar;
        weaken ($global_scalar = \$scalar);
    }
    # here $global_scalar is undef

When hashes’ back-references were moved, leave_scope was not updated
to account.  (For non-hash variables, it’s the mg_free call that takes
care of it.)  So in this case:

    {
        my %hash;
        weaken ($global_scalar = \%hash);
    }

$global_scalar would still reference a hash, but one marked PADSTALE.
Modifications to that hash through the reference would be visible the
next time the scope was entered.

scope.c
t/op/hash.t

diff --git a/scope.c b/scope.c
index 14664a2..d4615d1 100644 (file)
--- a/scope.c
+++ b/scope.c
@@ -911,6 +911,7 @@ Perl_leave_scope(pTHX_ I32 base)
                    av_clear(MUTABLE_AV(sv));
                    break;
                case SVt_PVHV:
+                   Perl_hv_kill_backrefs(aTHX_ MUTABLE_HV(sv));
                    hv_clear(MUTABLE_HV(sv));
                    break;
                case SVt_PVCV:
index b8aeaa7..34bfcde 100644 (file)
@@ -8,7 +8,7 @@ BEGIN {
 
 use strict;
 
-plan tests => 10;
+plan tests => 11;
 
 my %h;
 
@@ -168,3 +168,16 @@ is($destroyed, 1, 'Timely hash destruction with lvalue keys');
     delete $h{k}; # must be in void context to trigger the bug
     ok $normal_exit, 'freed hash elems are not visible to DESTROY';
 }
+
+# Weak references to pad hashes
+{
+    skip_if_miniperl("No Scalar::Util::weaken under miniperl", 1);
+    my $ref;
+    require Scalar::Util;
+    {
+        my %hash;
+        Scalar::Util::weaken($ref = \%hash);
+        1;  # the previous statement must not be the last
+    }
+    is $ref, undef, 'weak refs to pad hashes go stale on scope exit';
+}