Your message dated Sun, 31 May 2020 22:33:11 +0300
with message-id <[email protected]>
and subject line Re: Bug#940922: perl: iterating hash with "each", no write to 
hash but references got messed up
has caused the Debian Bug report #940922,
regarding perl: iterating hash with "each", no write to hash but references got 
messed up
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
940922: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=940922
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: perl
Version: 5.24.1-3+deb9u5
Severity: normal

I was trying to make program below as simple as possible, but I don't 
understand where is the bug introduced. 

The task is to make a copy of hash such that keys in new hash are made only out 
of alphanumerics and underscores "_". Hashes are nested. 

Here is the program: 

        #!/usr/bin/perl 

        use Data::Dumper; 

        sub hash_is_okey { 
                ref $_[0] eq "HASH" or return 0;  

                # for my $k (keys %{$_[0]}) { 
                #       my $v = ${$_[0]}{$k}; 

                while (my ($k, $v) = each %{$_[0]}) { 
                        $k =~ /\A[_[:alnum:]]+\z/ or return 0; 
                        hash_ok_or_scalar($v) or return 0; 
                }
                return 1;
        }

        sub hash_ok_or_scalar { return hash_is_okey($_[0]) || ! ref $_[0]; }

        sub make_hash_with_good_keys { 
                my ($x) = $_[0]; 

                hash_ok_or_scalar($x) and return $x; 

                ref $x eq "HASH" or die; 

                # copy hash "%{$x}" to new hash "%h" but make names good 
                my %h; 
                for my $k (keys %$x) { 

                        # copy "$k" to "$n", then make good name of "$n"
                        my $n = $k =~ s/[^[:alnum:]]/_/gr; 

                        $h{$n} = make_hash_with_good_keys($$x{$k}); 
                } 
                return \%h; 
        }

        my $original = { "top_level" => { "level down" => 123 } }; 
        my $with_good_keys = make_hash_with_good_keys($original); 

        print Dumper($original, $with_good_keys); 


and here is the result: 

        $VAR1 = {
                  'top_level' => {
                                   'level down' => 123
                                 }
                };
        $VAR2 = {
                  'top_level' => $VAR1->{'top_level'}
                };

In program hash "$with_good_keys" is made by:
* initializing new hash "%h", and then asigning to that hash new value
   or 
* plugging reference if "subhash" has good keys. 

But the result is bad, because "VAR2" has bad key "level down" -- contains 
space. 


If I change this part of program: 

                # for my $k (keys %{$_[0]}) { 
                #       my $v = ${$_[0]}{$k}; 

                while (my ($k, $v) = each %{$_[0]}) { 

to look like this (uncomment "for...keys", comment "while...each"): 

                for my $k (keys %{$_[0]}) { 
                        my $v = ${$_[0]}{$k}; 

                # while (my ($k, $v) = each %{$_[0]}) { 

then result is: 

        $VAR1 = {
                  'top_level' => {
                                   'level down' => 123
                                 }
                };
        $VAR2 = {
                  'top_level' => {
                                   'level_down' => 123
                                 }
                };

Now "$VAR2" is a copy with names modified as expected. 

This is extremely strange, because I don't write to hash I am iterating over 
with "while...each". I tried to
resolve this myself for many hours, but I failed. 



-- System Information:
Debian Release: 9.11
  APT prefers oldstable-updates
  APT policy: (500, 'oldstable-updates'), (500, 'oldstable')
Architecture: amd64 (x86_64)

Kernel: Linux 4.9.0-9-amd64 (SMP w/4 CPU cores)
Locale: LANG=pl_PL.UTF-8, LC_CTYPE=pl_PL.UTF-8 (charmap=UTF-8), 
LANGUAGE=pl_PL.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages perl depends on:
ii  dpkg               1.18.25
ii  libperl5.24        5.24.1-3+deb9u5
ii  perl-base          5.24.1-3+deb9u5
ii  perl-modules-5.24  5.24.1-3+deb9u5

Versions of packages perl recommends:
ii  netbase  5.4
pn  rename   <none>

Versions of packages perl suggests:
pn  libterm-readline-gnu-perl | libterm-readline-perl-perl  <none>
pn  make                                                    <none>
pn  perl-doc                                                <none>

-- no debconf information

--- End Message ---
--- Begin Message ---
On Sun, Sep 22, 2019 at 01:39:30AM +0200, Leszek Dubiel wrote:
> Package: perl
> Version: 5.24.1-3+deb9u5
> Severity: normal
> 
> I was trying to make program below as simple as possible, but I don't 
> understand where is the bug introduced. 
> 
> The task is to make a copy of hash such that keys in new hash are made only 
> out of alphanumerics and underscores "_". Hashes are nested. 

[...]

> This is extremely strange, because I don't write to hash I am iterating over 
> with "while...each". I tried to
> resolve this myself for many hours, but I failed. 

Hi, in the first hash_ok_or_scalar() check, the each() iterator in
hash_is_okey() for the second level hash is left incomplete by the
'return 0' when the first (and only) item is deemed bad.

When make_hash_with_good_keys() is then called recursively to make a copy
of the second level hash, it calls hash_is_okey() again on the original
second level hash, and each() continues where it left off, yielding
nothing. So hash_is_okey() returns 1 as if there's nothing wrong with
the hash, and make_hash_with_good_keys() happily returns it unchanged.

Hope that helps, not sure if I explained it clearly enough. Anyway,
this is not a bug in Perl so closing.
-- 
Niko Tyni   [email protected]

--- End Message ---

Reply via email to