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

I was trying to answer a question on the perl beginners list (see http://learn.perl.org/) when I dumped core with the following code.

use strict; my %allusers = ( 'users' => { 'user' => 'Test Account', '*Crudles' => 'Hello World', 'Crud' => 'Another Test', '*test' => 'Crud User' } ); foreach my $key ( %{ $allusers{ users } } ) { delete $allusers{ users }{ $key } if '*' eq substr $key, 0, 1; } # result: $ perl test.pl 0 [main] perl 374831 open_stackdumpfile: Dumping stack trace to +PERL.EXE.Stackdump Segmentation fault (core dumped)

perl -v output:

This is perl, v5.6.1 built for cygwin-multi Copyright 1987-2001, Larry Wall Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 5 source ki +t. Complete documentation for Perl, including FAQ lists, should be found +on this system using `man perl' or `perldoc perl'. If you have access to + the Internet, point your browser at http://www.perl.com/, the Perl Home Pa +ge.

This was cygwin running on Windows 98. Even when trying to run this at a DOS prompt, I get a modal dialog box that reads:

This program has performed an illegal operation and will be shut down. If the problem persists, contact the program vendor. PERL caused an invalid page fault in module PERL56.DLL at 017f:280705f1. Registers: yada, yada, yada

When running under DOS, it's 5.6.0. Is this a known bug? 'perl -c test.pl' tells me that my syntax is okay.

Cheers,
Ovid

Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Replies are listed 'Best First'.
Re: Why does this dump core?
by danger (Priest) on Dec 11, 2001 at 15:34 UTC

    This is likely related to this change in 5.6 (from perldelta):

    =head2 delete(), each(), values() and hash iteration are faster The hash values returned by delete(), each(), values() and hashes in a list context are the actual values in the hash, instead of copies. This results in significantly better performance, because it eliminate +s needless copying in most situations.

    Previously, only copies were used, which meant that foreach-aliasing didn't really alias into the real hash values:

    my %hash = (name => 'andrew', beer => 'Ale'); foreach my $KV (%hash) { print ">>$KV<<\n"; $hash{$KV} = 'Dark Ale' if $KV eq 'beer'; } __END__ # with 5.00503: >>name<< >>andrew<< >>beer<< >>Ale<< # with 5.6.1 >>beer<< >>Dark Ale<< >>name<< >>andrew<<

    As you can see, with 5.005, even after we've changed the value for the key 'beer', we still get the old value because it was a copy. In 5.6 we get the new value because it is an alias into the hash. Now, in your situation, after deleting the key '*test' the next iteration involves an alias to a non-existing value and this is causing a problem for perl (which with -w gives "attempt to free unreferenced scalar", and a segfault otherwise).

Re: Why does this dump core?
by blakem (Monsignor) on Dec 11, 2001 at 13:37 UTC
    Just a couple data points for you... On 5.00503 for linux, it doesn't dump. With 5.6.1 it does. However, with warnings on in 5.6.1 I get this: (note, lines 13 & 14 refer to the foreach stanza)
    % perl5.6.1 -w test.pl Use of uninitialized value in substr at test.pl line 14. Attempt to free unreferenced scalar at test.pl line 13. Use of uninitialized value in substr at test.pl line 14. Attempt to free unreferenced scalar at test.pl line 13. # other invocations.... % perl5.00503 -w test.pl [nothing] % perl5.00503 test.pl [nothing] % perl5.6.1 test.pl Segmentation fault (core dumped)
    Update: As crazy noted... a well placed keys() in your foreach loop seems to solve the problem.....

    Update 2: It looks like deleting the key before you get to the corresponding value in the foreach loop is causing problems...

    #!/usr/bin/perl use strict; ### show what we're looping over (a,1,b,2,c,3) my %hash = (a=>1, b=>2, c=>3); for (%hash) { print "OK: $_\n"; } ### check the value *before* we attempt to delete the key ### i.e. 1 before a, 2 before b, 3 before c %hash = (a=>1, b=>2, c=>3); for (reverse %hash) { substr $_, 0, 1; delete($hash{$_}) if /[a-z]/; print "Still-OK: $_\n"; } ### emulate your structure where we can potentially delete ### a key first, then loop over the value associated with it %hash = (a=>1, b=>2, c=>3); for (%hash) { substr $_, 0, 1; # <== segfaults here when testing value associated +with deleted key delete($hash{$_}) if /[a-z]/; print "Not-OK: $_\n"; } __END__ =head1 OUTPUT OK: a OK: 1 OK: b OK: 2 OK: c OK: 3 Still-OK: 3 Still-OK: c Still-OK: 2 Still-OK: b Still-OK: 1 Still-OK: a Not-OK: a Not-OK: Segmentation fault (core dumped)

    -Blake

Re: Why does this dump core?
by growlf (Pilgrim) on Dec 11, 2001 at 13:54 UTC
    That is interesting, Ovid. ..and yes, it seems to do the same on my cygwin (though, notice they have updated the Cygwin-Perl significantly in the last several updates of Cygwin). Meanwhile, the following works fine:

    use strict; my %allusers = ( 'users' => { 'user' => 'Test Account', '*Crudles' => 'Hello World', 'Crud' => 'Another Test', '*test' => 'Crud User' } ); foreach my $key (keys %allusers ) { delete $allusers {'users'}{$key} if '*' eq substr $key, 0, 1; }
    I think you found a bug worth reporting to the cygwin team, as it does not appear anywhere in the docs there or elsewhere that I can find and appears enough obscure that no one probably noticed...

    *G*
(crazyinsomniac) Re: Why does this dump core?
by crazyinsomniac (Prior) on Dec 11, 2001 at 13:37 UTC
    I don't know ;( this is what I get (still weird)
    update: did you mean to call here (foreach my $key ( %{ $allusers{ users } } ))?
    #!/usr/bin/perl -w use strict; my %allusers = ( 'users' => { 'user' => 'Test Account', '*Crudles' => 'Hello World', 'Crud' => 'Another Test', '*test' => 'Crud User' } ); foreach my $key ( %{ $allusers{ users } } ) { delete $allusers{ users }{ $key } if '*' eq substr $key, 0, 1; } __END__ F:\dev>perl -c ovidcoredump.pl ovidcoredump.pl syntax OK F:\dev>perl ovidcoredump.pl Use of uninitialized value in substr at ovidcoredump.pl line 14. Attempt to free unreferenced scalar at ovidcoredump.pl line 13. Use of uninitialized value in substr at ovidcoredump.pl line 14. Attempt to free unreferenced scalar at ovidcoredump.pl line 13. F:\dev>perl -v This is perl, v5.6.1 built for MSWin32-x86-multi-thread (with 1 registered patch, see perl -V for more detail) Copyright 1987-2001, Larry Wall Binary build 628 provided by ActiveState Tool Corp. http://www.ActiveS +tate.com Built 15:41:05 Jul 4 2001 Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 5 source ki +t. Complete documentation for Perl, including FAQ lists, should be found +on this system using `man perl' or `perldoc perl'. If you have access to + the Internet, point your browser at http://www.perl.com/, the Perl Home Pa +ge. F:\dev>f:\indigoperl\bin\perl ovidcoredump.pl Use of uninitialized value in substr at ovidcoredump.pl line 15. Attempt to free unreferenced scalar at ovidcoredump.pl line 13. Use of uninitialized value in substr at ovidcoredump.pl line 15. Attempt to free unreferenced scalar at ovidcoredump.pl line 13. F:\dev>f:\indigoperl\bin\perl -v This is perl, v5.6.0 built for MSWin32-x86-multi-thread Copyright 1987-2000, Larry Wall Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 5.0 source +kit. Complete documentation for Perl, including FAQ lists, should be found +on this system using `man perl' or `perldoc perl'. If you have access to + the Internet, point your browser at http://www.perl.com/, the Perl Home Pa +ge. F:\dev> bash-2.05$ perl ovid.pl bash-2.05$ perl -c ovid.pl ovid.pl syntax OK bash-2.05$ perl -v This is perl, version 5.005_03 built for i386-freebsd Copyright 1987-1999, Larry Wall Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 5.0 source +kit. Complete documentation for Perl, including FAQ lists, should be found +on this system using `man perl' or `perldoc perl'. If you have access to + the Internet, point your browser at http://www.perl.com/, the Perl Home Pa +ge. bash-2.05$

     
    ___crazyinsomniac_______________________________________
    Disclaimer: Don't blame. It came from inside the void

    perl -e "$q=$_;map({chr unpack qq;H*;,$_}split(q;;,q*H*));print;$q/$q;"

(Ovid) Re: Why does this dump core?
by Ovid (Cardinal) on Dec 11, 2001 at 21:30 UTC

    I was wondering if deleting keys while iterating over a hash was reallocating the buckets and perhaps Perl was then trying to access memory that's not there. According to Adding or removing keys while iterating over a hash, this is not the case. I can't add, but I should have no problem deleting. Both merlyn and Dominus state that. However, what's vexing about this is that it appears similar to a Perl4 issue where deleting from a hash while iterating over it was verboten. This was fixed in Perl5.

    Forgetting the keys should certainly cause the code to fail, but generating a core dump? That's certainly going to cause some people to panic :)

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      That's not the same problem. Your new problem is that you aren't using an iterator (keys(), values(), each()), but just directly evaluating the hash in list context --- and in 5.6.1 that results in the values part of the returned list being the actual values in the hash (instead of copies, as per my previous post). This shouldn't be a real problem because the normal way to do what you are trying to do would be to use keys() in the foreach loop to just iterate over the keys (and thus never be in the position of having an alias to a hash-value that no longer exists). There is no 'forgetting' of keys going on in your problem, your code is deleting a *value* that the foreach-list already has an alias to (because you used foreach (%hash) instead of foreach (keys %hash)).

      Granted, this shouldn't segfault --- it doesn't when warnings are turned on (at least on 5.6.1 on linux). However, you can cause the same sort of behaviour on an array if you foreach over a list of array elements and remove (splice()) an element from the array before we get there in the list (segfaults on 5.00503 and 5.6.1, linux):

      my @array = (0,1,2); foreach my $el ($array[0],$array[1],$array[2]){ print ">>$el<<\n"; splice(@array,1,1) if $el == 0; }
Re: Why does this dump core?
by blakem (Monsignor) on Dec 17, 2001 at 06:09 UTC