in reply to How come @_ gets changed here?

The behavior of this script in perl 5.26 is so weird that it seems like it must be a bug.
Before calling the sub test_this @arr: 1 2 3 4 5 6 7 8 9 10 Inside the sub, before the map @arr: 1 2 3 4 5 6 7 8 9 10 Inside the sub, before the map @_ = 1 2 3 4 5 6 7 8 9 10 Inside the sub, after the map @arr: 2 4 6 8 10 12 14 16 18 20 Use of uninitialized value $_[0] in join or string at foo line 11. Use of uninitialized value $_[3] in join or string at foo line 11. Use of uninitialized value $_[6] in join or string at foo line 11. Use of uninitialized value $_[9] in join or string at foo line 11. Inside the sub, after the map @_ = _ Use of uninitialized value $_[0] + in join or string at foo line 11. _ Use of uninitialized value $_[3] in join or string at foo line 11. _ Use of uninitialized value $_[6] in join or string at foo line 11. After calling the sub test_this @arr: 2 4 6 8 10 12 14 16 18 20
If I throw in print Dumper(@_), I get this:
panic: attempt to copy freed scalar 7fe03e8040b0 to 7fe03e82c858 at /o +pt/local/lib/perl5/5.26/darwin-thread-multi-2level/Data/Dumper.pm lin +e 602.
Anyone know what's going on?

Replies are listed 'Best First'.
Re^2: How come @_ gets changed here?
by haukex (Archbishop) on Jun 10, 2017 at 15:37 UTC

    Interesting, a bisect with a test program something like this:

    my @a=(3); sub x { @a = map {$_*2} @_; "@_" eq "6" or die } &x(@a);

    says that the first bad commit is a5f4850559, which makes v5.24.0, or more specifically v5.23.2, the first version with this behavior. Since that commit is heavy on the internals and I'm not an expert on that, I can't say more at the moment, although it does seem like a regression to me.

      It's not particularly a regression. Perl suffers from a particular over-arching bug, which is hard to fix (which is why it hasn't been fixed yet): elements on perl's execution stack are not reference counted. This means that if you empty something like an array whose elements are on the stack (and will have been aliased to elements of @_ if this is a function call), and if nothing else holds a reference count to those elements, then they will be prematurely freed (and possibly re-allocated) while still accessible.

      That commit merely causes that bug to show up where previously it happened to be masked. For example in 5.22.0 with this code:

      my @a=(3,4); sub x { @a = (); print "[$_]" for @_; print "\n"; } x(@a);
      you get:
      $ perl5220 -w ~/tmp/p Use of uninitialized value $_ in concatenation (.) or string at /home/ +davem/tmp/p line 9. Use of uninitialized value $_ in concatenation (.) or string at /home/ +davem/tmp/p line 9. [][]

      Dave.

        Thanks for the info! I remember seeing references to the "the stack isn't refcounted bug" from my casual lurking on P5P - I just checked again and recent references appear to be Stack refcount synopsis and perl #114372. If it's unclear when it'll be fixed, maybe it would make sense to include a blurb about the nature of the bug in the documentation, something like what you wrote here in this thread?

        So what's the take-away here? If your sub has to put stuff in variables outside its own scope, don't also pass those variables as parameters?
Re^2: How come @_ gets changed here?
by LanX (Saint) on Jun 10, 2017 at 15:37 UTC
    I guess they did some optimization to speed up code execution and never expected/tested such a weird case where the same values are at LHS as closed overs and at RHS as aliases.

    The gaps indicate side effects from changing the execution/evaluation order.

    Edit: like not caching a list of the map but iterating and setting each element directly.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!