From: Dave Mitchell Date: Thu, 1 May 2003 21:06:57 +0000 (+0100) Subject: [perl #3096] undefing hash with object values X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=2f86008e342644f19f6a5b7136a5027c19cae4c1;p=p5sagit%2Fp5-mst-13.2.git [perl #3096] undefing hash with object values Message-ID: <20030501200657.GA25456@fdgroup.com> p4raw-id: //depot/perl@19424 --- diff --git a/hv.c b/hv.c index e018a75..f5508bf 100644 --- a/hv.c +++ b/hv.c @@ -1728,8 +1728,6 @@ Perl_hv_clear(pTHX_ HV *hv) } hfreeentries(hv); - xhv->xhv_fill = 0; /* HvFILL(hv) = 0 */ - xhv->xhv_keys = 0; /* HvKEYS(hv) = 0 */ xhv->xhv_placeholders = 0; /* HvPLACEHOLDERS(hv) = 0 */ if (xhv->xhv_array /* HvARRAY(hv) */) (void)memzero(xhv->xhv_array /* HvARRAY(hv) */, @@ -1758,6 +1756,12 @@ S_hfreeentries(pTHX_ HV *hv) riter = 0; max = HvMAX(hv); array = HvARRAY(hv); + /* make everyone else think the array is empty, so that the destructors + * called for freed entries can't recusively mess with us */ + HvARRAY(hv) = Null(HE**); + HvFILL(hv) = 0; + ((XPVHV*) SvANY(hv))->xhv_keys = 0; + entry = array[0]; for (;;) { if (entry) { @@ -1771,6 +1775,7 @@ S_hfreeentries(pTHX_ HV *hv) entry = array[riter]; } } + HvARRAY(hv) = array; (void)hv_iterinit(hv); } @@ -1799,8 +1804,6 @@ Perl_hv_undef(pTHX_ HV *hv) } xhv->xhv_max = 7; /* HvMAX(hv) = 7 (it's a normal hash) */ xhv->xhv_array = 0; /* HvARRAY(hv) = 0 */ - xhv->xhv_fill = 0; /* HvFILL(hv) = 0 */ - xhv->xhv_keys = 0; /* HvKEYS(hv) = 0 */ xhv->xhv_placeholders = 0; /* HvPLACEHOLDERS(hv) = 0 */ if (SvRMAGICAL(hv)) diff --git a/t/op/undef.t b/t/op/undef.t index 1d16994..04cac52 100755 --- a/t/op/undef.t +++ b/t/op/undef.t @@ -5,7 +5,7 @@ BEGIN { @INC = '../lib'; } -print "1..28\n"; +print "1..36\n"; print defined($a) ? "not ok 1\n" : "ok 1\n"; @@ -85,3 +85,20 @@ print $@ =~ /^Modification of a read/ ? "ok 23\n" : "not ok 23\n"; eval 'undef tcp'; print $@ =~ /^Can't modify constant item/ ? "ok 28\n" : "not ok 28\n"; } + +# bugid 3096 +# undefing a hash may free objects with destructors that then try to +# modify the hash. To them, the hash should appear empty. + +$test = 29; +%hash = ( + key1 => bless({}, 'X'), + key2 => bless({}, 'X'), +); +undef %hash; +sub X::DESTROY { + print "not " if keys %hash; print "ok $test\n"; $test++; + print "not " if values %hash; print "ok $test\n"; $test++; + print "not " if each %hash; print "ok $test\n"; $test++; + print "not " if defined delete $hash{'key2'}; print "ok $test\n"; $test++; +}