Open dpchrist opened 3 years ago
I have reproduced the problem on FreeBSD, so the problem is not OS-specific. It is not clear to me what part of the problem lies in threads::shared
and what in Data::Dumper
(specifically, in $Data::Dumper::Maxrecurse
).
When checking for recursion, Data::Dumper checks for matching addresses on the references (the 0x... in HASH(0x55d2f701d178)), but for threads::shared (and presumably other tied object implementations), a new reference is returned for each recursive reference:
$ ./perl -Ilib -Mthreads -Mthreads::shared -le 'my %a : shared; $a{foo} = \%a; print \%a; my $x = $a{foo}; print $x->{foo}; print $x->{foo}{foo}'
HASH(0x55a1b57532f8)
HASH(0x55a1b5749088)
HASH(0x55a1b583e938)
while for a non-tied object the references are all equivalent:
$ ./perl -Ilib -Mthreads -Mthreads::shared -le 'my %a; $a{foo} = \%a; print \%a; my $x = $a{foo}; print $x->{foo}; print $x->{foo}{foo}'
HASH(0x5619388e52e8)
HASH(0x5619388e52e8)
HASH(0x5619388e52e8)
I think threads::shared caching a weak reference to each object and returning that instead of a new reference each time would work, but it would cost extra memory and CPU over the the current implementation for non-recursive structures.
When I ran into problems with Data::Dumper and shared variables, the crux was to look at the return value of List::Util::refaddr() for unshared variables and the return value of threads::shared::is_shared() for shared variables. I built a sawed-off Data::Dumper that used the following utility function to detect loops:
#
sub refaddr(;$) { local $ = @ ? $[0] : $_;
my $r = defined && ref($_)
? (is_shared($_) || refaddr($_))
: undef;
return $r;
}
My WAG is that Data::Dumper needs something like the above inserted in just the right place(s). I looked and made some stabs at it, but never got it right.
David