http://qs321.pair.com?node_id=11142844

Krambambuli has asked for the wisdom of the Perl Monks concerning the following question:

Within BackupPC::Storage::Text, there is some code like
if ( exists($newConf->{$var}) ) { my $d = Data::Dumper->new([$newConf->{$var}], [*va +lue]); $d->Indent(1); $d->Terse(1); $d->Sortkeys(1); my $value = $d->Dump; $value =~ s/(.*)\n/$1;\n/s; $contents .= "\$Conf{$var} = " . $value; $done->{$var} = 1; }
This works fine for older versions of Data::Dumper, but fails for newer ones.

Replacing the line referring Data::Dumper with
my $d = Data::Dumper->new([$newConf->{$var}], \[*value]);
solves the issue, but I'm not sure I understand why exactly.

In particular, I would like to understand if it's BackupPC doing something that it shouldn't when using [*value], or if it is Data::Dumper that broke the rules by doing things differently now.

(Later edit) Looks like the correct question is like

should [*value] be a list or an arrayref?

Replies are listed 'Best First'.
Re: BackupPC or Data::Dumper playing foul...?
by hv (Prior) on Apr 08, 2022 at 17:47 UTC

    It would help if you could define what you mean by "works fine" and "fails", ideally by giving an sscce.

    According to the docs, the intention when supplying [*value] is that the output will assign a name appropriate to the type of the value: if you give it a hashref to dump, it will assume it actually represents a hash called %value, for example. It appears this has been broken for a long time, and was recently fixed - a quick scan of the Changes file (https://metacpan.org/dist/Data-Dumper/changes) suggests it may have been the very recent 2.182_51 change.

    With latest bleadperl (which has v2.184, not yet available on CPAN), I get:

    % perl -MData::Dumper -e ' my %h = (one => 1); $h{refone} = \$h{one}; # make it a self-referential structure my $d = Data::Dumper->new([\%h], [*value]); $d->Indent(1); $d->Terse(1); $d->Sortkeys(1); print $d->Dump; ' ( 'one' => 1, 'refone' => \$main::value{'one'} )

    .. which I believe is the correct intended output. With older versions (back at least as far as maint-5.8) I get instead:

    { 'one' => 1, 'refone' => \$VAR1->{'one'} }

    .. which is wrong, since it refers to $VAR1 instead of to %value.

    By changing it to \[*value] I guess you have turned it into something Dump() does not recognise, so it ignores it. The result is that you get the same output as the previous broken behaviour. You can achieve the same by removing the [*value] arrayref altogether.

    (I'm slightly worried that the changelog states that this was a fix only for the XS code: additionally calling $d->Useperl(1) before the Dump() call does not change the output in either case for me, so it's possible I'm completely misunderstanding what's going on.)

    Hugo

      I'm pretty sure it is related to the Changes that you are referring to.
      Simple code to play with and check the issue:

      #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my $newConf = { 'FullKeepCnt' => [ 4 ] }; print "Original structure: ", Dumper( $newConf ); foreach my $var ( sort(keys(%$newConf)) ) { my $d1 = Data::Dumper->new([$newConf->{$var}], \[*value]); print "\nd1: ", Dumper( $d1 ); my $value1 = $d1->Dump; print "\nvalue 1: $value1\n"; my $d2 = Data::Dumper->new([$newConf->{$var}], [*value]); $d2->Useperl(0); print "\nd2: ", Dumper( $d2 ); my $value2 = $d2->Dump; print "\nvalue2: $value2\n"; }
      The output that matters is
      value2: @main::value = ( 4 );
      whereas the initial arrayref is what BackupPC needs and expects. (The list it gets back now via DumpXS actually ruins BackupPCs config files when using the web interface for editing...)

      The pure Perl version returns a list, and so I guess that that's what it should be. My current understanding is that BackupPC did it wrongly for many years, and still does, but was able to get away with it because DumpXS within Data::Dumper was buggy. Now that Data::Dumper is corrected, BackupPCs needs to patch it's code.

      Afaict, \[*value] works fine, both with DumpXS and pure Perl. But I'm not fully sure that that's 'the best' patch to be done, even if it works for me.

        Well this all depends on how the output from Dump (or Dumper) is going to be used, which you don't show; but yes, if the intent is to eval() the output to store in a scalar, passing [*value] is exactly the wrong thing to do.

        Even if \[*value] works for you now, it is an invalid parameter for Data::Dumper, so it's likely that another future version will actually check that and complain about it. The correct fix, as I mentioned in my original reply, is to remove the second parameter to new() altogether: just make it Data::Dumper->new([$newConf->{$var}]).