Closed p5pRT closed 13 years ago
Attempting to access a hash entry where an object was just removed from during that object's destructor causes a panic:
#!/usr/bin/env perl use strict; use warnings; use Test::More;
my $called;
{ my %cache; sub get { $cache{$_[0]} } sub store { $cache{$_[0]} = $_[1] } sub remove { delete $cache{$_[0]}; return } }
{ package Thing; sub new { my $class = shift; bless { name => $_[0] }\, $class } sub name { shift->{name} } sub DESTROY { my $self = shift; my $thing = ::get($self->name); $called = 1; } }
store(foo => Thing->new('foo')); remove('foo');
is($called\, 1\, "got through the DESTROY method");
done_testing;
__END__ (in cleanup) panic: attempt to copy freed scalar d5f500 to d5f4e8 at test.pl line 21. not ok 1 - got through the DESTROY method # Failed test 'got through the DESTROY method' # at test.pl line 29. # got: undef # expected: '1' 1..1 # Looks like you failed 1 test of 1.
Bisecting points to this commit as causing the issue:
commit f50383f58716bc0faa50de094d47cad8ad3fcbdb Author: Ton Hospel \me\-02@​ton\.iguana\.be Date: Thu May 19 17:05:16 2011 -0700
[perl #85026] Deleting the current iterator in void context
Looking at the delete code I see another strange thing. If the delete
of the current iterator is done with the G_DISCARD flag\, the corres-
ponding value is not freed and survives until the lazy deleted entry
gets removed on the next hash iteration. This is easily demonstrated
like this:
perl -wle '
sub DESTROY { print "DESTROY" }
%a=(a=>bless[]);
each %a;
delete $a{a};
print "END"
'
This prints:
END
DESTROY
notice the difference with:
perl -wle '
sub DESTROY { print "DESTROY" }
%hash = (a => bless[]);
each %hash;
$dummy = delete $hash{a}; $dummy = 0;
print "END"
'
This prints:
DESTROY
END
This is easily solved by always replacing the deleted entry value with
&PL_sv_placeholder. It actually simplifies the code a bit except for the
fact that the mro_method_changed from free_hash_ent now has to be done
in hv_delete
Fixed locally; running tests....
The RT System itself - Status changed from 'new' to 'open'
Fixed with commit 7058221.
@cpansprout - Status changed from 'open' to 'resolved'
Migrated from rt.perl.org#99660 (status was 'resolved')
Searchable as RT99660$