#1012375 perl: Data::Dumper vs. shared and unshared circular loops

Package:
perl
Source:
perl
Description:
Larry Wall's Practical Extraction and Report Language
Submitter:
David Christensen
Date:
2022-06-05 21:03:03 UTC
Severity:
normal
#1012375#5
Date:
2022-06-05 20:59:54 UTC
From:
To:
Dear Maintainer,

Data::Dumper has problems with data structures built with shared arrays
and shared hashes that contain self-referencing loops.  See console
session, below.

I suspect the problem is that Data::Dumper is using reference
stringification or Scalar::Util::refaddr to remember references when
walking data structures.

I have found that using threads::shared::is_shared provides correct
results.

These problems are not Debian-specific; they have existed in Perl for
many years.

David



2022-06-05 13:56:30 dpchrist@laalaa ~/sandbox/perl
$ cat /etc/debian_version ; uname -a
11.3
Linux laalaa 5.10.0-14-amd64 #1 SMP Debian 5.10.113-1 (2022-04-29) x86_64 GNU/Linux

2022-06-05 13:57:36 dpchrist@laalaa ~/sandbox/perl
$ dpkg-query --show perl
perl	5.32.1-4+deb11u2

2022-06-05 13:57:44 dpchrist@laalaa ~/sandbox/perl
$ perl -MData::Dumper -e 'print $Data::Dumper::VERSION, "\n"'
2.174_01

2022-06-05 13:58:08 dpchrist@laalaa ~/sandbox/perl
$ cat Data-Dumper-vs-shared-unshared-circular-loops.t
#!/usr/bin/env perl
#######################################################################
# $Id: Data-Dumper-vs-shared-unshared-circular-loops.t,v 1.2 2022/06/05 20:56:22 dpchrist Exp $
# by David Paul Christensen dpchrist@holgerdanske.com
# Public Domain
#
# Demonstration of Data::Dumper->Dump() for data structures built with
# non-shared and shared variables with self-referencing loops.
#======================================================================

use strict;
use warnings;
use threads;
use threads::shared;
use Data::Dumper;
use Getopt::Long;
use Test::More;

my $d;

my @ca;
push @ca, \@ca;

my %ch;
$ch{loop} = \%ch;

my $cs;
$cs = \$cs;

my @csa :shared;
push @csa, \@csa;

my %csh :shared;
$csh{loop} = \%csh;

my $css :shared;
$css = \$css;

eval { chomp($d = Data::Dumper->Dump([$cs], ['cs'])) };
if ($@) { fail("cs: $@") } else { pass("cs: $d") };

eval { chomp($d = Data::Dumper->Dump([$css], ['css'])) };
if ($@) { fail("css: $@") } else { pass("css: $d") };

eval { chomp($d = Data::Dumper->Dump([\@ca], ['*ca'])) };
if ($@) { fail("ca: $@") } else { pass("ca: $d") };

eval { chomp($d = Data::Dumper->Dump([\@csa], ['*csa'])) };
if ($@) { fail("csa: $@") } else { pass("csa: $d") };

eval { chomp($d = Data::Dumper->Dump([\%ch], ['*ch'])) };
if ($@) { fail("ch: $@") } else { pass("ch: $d") };

eval { chomp($d = Data::Dumper->Dump([\%csh], ['*csh'])) };
if ($@) { fail("csh: $@") } else { pass("csh: $d") };

done_testing;
#######################################################################

2022-06-05 13:58:12 dpchrist@laalaa ~/sandbox/perl
$ perl Data-Dumper-vs-shared-unshared-circular-loops.t
ok 1 - cs: $cs = \$cs;
ok 2 - css: $css = \$css;
ok 3 - ca: @ca = (
#         \@ca
#       );
not ok 4 - csa: Recursion limit of 1000 exceeded at /usr/lib/x86_64-linux-gnu/perl/5.32/Data/Dumper.pm line 232.
#
#   Failed test 'csa: Recursion limit of 1000 exceeded at /usr/lib/x86_64-linux-gnu/perl/5.32/Data/Dumper.pm line 232.
# '
#   at Data-Dumper-vs-shared-unshared-circular-loops.t line 49.
ok 5 - ch: %ch = (
#         'loop' => \%ch
#       );
not ok 6 - csh: Recursion limit of 1000 exceeded at /usr/lib/x86_64-linux-gnu/perl/5.32/Data/Dumper.pm line 232.
#
#   Failed test 'csh: Recursion limit of 1000 exceeded at /usr/lib/x86_64-linux-gnu/perl/5.32/Data/Dumper.pm line 232.
# '
#   at Data-Dumper-vs-shared-unshared-circular-loops.t line 55.
1..6
# Looks like you failed 2 tests of 6.