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

[This post delves into the internals of Perls. Most won't find it useful, but some might find it interesting.]

I've used the following to process the contents of an array while emptying it:

f( splice(@a) )

Someone asked what @a, @a=() did on StackOverflow. Well, that's the what the title of their question was, but the actual question was a bit different. But I thought it might be an alternative to splice(@a), so I put it to the test.

$ perl -e' use strict; use warnings; use feature qw( say ); my @a = qw( a b c d ); say for @a, @a=(); say "--"; say for @a; ' Use of freed value in iteration at -e line 7.

That was a first for me! Anyone want to venture a guess as to why it does that?

Note that the problem is not specific to loops, contrary to what your research might initially lead you to believe.

$ perl -e' use strict; use warnings; use feature qw( say ); my @a = qw( a b c d ); my @b = ( @a, @a=() ); say for @b; say "--"; say for @a; ' Use of uninitialized value $_ in say at -e line 8. Use of uninitialized value $_ in say at -e line 8. Use of uninitialized value $_ in say at -e line 8. Use of uninitialized value $_ in say at -e line 8. --

Hint: The following avoids the problem:

$ perl -e' use strict; use warnings; use feature qw( say ); my @a = qw( a b c d ); my $r = sub{ \@_ }->(@a); say for @a, @a=(); say "--"; say for @a; ' a b c d --

I'll post the answer.

Replies are listed 'Best First'.
Re: Use of freed value
by ikegami (Patriarch) on Jun 26, 2019 at 16:48 UTC

    You might have checked perldiag, which leads with "Perhaps you modified the iterated array within the loop?" But that's not the case. As the question mark suggests, it's giving you the common case that results in this error, but it's not describing the real problem.


    Perl uses reference counting as its garbage collection mechanism. For every place a scalar is referenced, its reference counter is incremented. When something stops referencing a scalar, its reference counter is decremented. If the reference counter reaches zero, the value is destroyed and freed.

    Well, there's an exception to that: When placing a value on the stack, it's reference count isn't incremented. I don't know why, but that's the way it is.

    This means that returning values that you no longer reference is tricky. Any XS programmer knows that if you want to return a scalar that you no longer reference, you make it a mortal rather than decrementing its reference count (which would free it prematurely). Making a scalar mortal adds it to a list of scalars to free in the caller once the caller has had a chance to take ownership of the scalar by incrementing its reference count.

    This also means that the elements of @a in my code are freed (by @a=()) while they are on the stack waiting for the loop to start (first snippet) or to be assigned to @b (second snippet).

    This is just two of many bugs caused by reference counting not applying to the stack. Fun!

Re: Use of freed value
by shmem (Chancellor) on Jun 26, 2019 at 17:35 UTC
    Ah, ikegami already posted the answer... in a ticket in the perl bug tracker dave_the_m(?) says
    a (more or less unfixable) design flaw in perl's internals: the stack not being ref counted.

    and shows this code example

    %h = qw( a 1 b 2 ); f(%h); sub f { %h = qw(c 3); # uh oh :-( use Carp; Carp::confess(); } __END__ at /home/davem/tmp/p line 10. main::f("a", "", "b", 3) called at /home/davem/tmp/p line 5

    which is akin to those ikegami posted.

    For perl v5.26 the output is slightly different:

    at baz.pl line 10. main::f("a", "", "b", "") called at baz.pl line 5

    This might be due to other fixes than the underlying issue, which is still there.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: Use of freed value
by LanX (Saint) on Jun 26, 2019 at 16:51 UTC
    My guess it's a variation of the call($x++,$x++) side effect problem.

    The @a has no refcount anymore after "emptying" it

    The $r in the hint solved it.

    Just a guess, no time to dig into the guts.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      call($x++, $x++) works in an unsurprising manner.

      $ perl -e'$x=3; CORE::say for $x++, $x++' 3 4

      I think you're referring to the oddities of call(++$x, ++$x).

      $ perl -e'$x=3; CORE::say for ++$x, ++$x' 5 5

      or

      $ perl -e'$x=3; CORE::say for $x, $x++' 4 3

      These occur because $x and ++$x (and --$x) add the scalar $x itself to the stack rather than a copy. $x++ (and $x--) necessarily add a copy of the original value.

      Well, the problem is related to the scalars themselves being on the stack, so the explanations are indeed related. But that's just the precondition for the problem, not the answer itself.

        > I think you're referring to the oddities of

        Yes

        > so the explanations are indeed related. But that's just the precondition for the problem, not the answer itself.

        Well I tend to avoid such side effects because of this experience.

        I don't necessarily need to know why I suffer after crossing the red line.

        Update

        And it's a pretty good guess inside the 15 min window you left us before answering it yourself. ;)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice