in reply to Re^4: Use of freed value in iteration
in thread Use of freed value in iteration

I wonder if this is an example of the stack not being ref-counted. Hopefully someone is able to test with a recent 5.39 perl with the ref-counted stack enabled.

(Edited grammar after posting).

Replies are listed 'Best First'.
Re^6: Use of freed value in iteration
by choroba (Cardinal) on Feb 13, 2024 at 12:46 UTC
    > I wonder if this is an example of the stack not being ref-counted

    I discussed it with Pali and he thinks it is a refcounting problem. It seems when iterating over values, the refcount of the current element is incremented, but all other elements keep their refcounts unchanged. Therefore, iterating over something doesn't prevent non-current elements from destruction. To see what happens,

    use Devel::Peek;
    and prepend
    Dump $hr3;
    to the beginning of the loop.

    For loop is implemented by a stack: pp_hot.c and pp_ctl.c.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      "It seems when iterating over values, the refcount of the current element is incremented, but all other elements keep their refcounts unchanged. Therefore, iterating over something doesn't prevent non-current elements from destruction."
      That seems like a good feature instead of a problem. If an element disappears I want to know about it. If I don't care if it disappears I can make copies of the elements beforehand. To me the problem seems to be that the deleted element can erroneously reappear as something else if it's memory location is reused. For hashes this can be avoided by iterating over keys and checking if the key still exists when it is to be used.

        1) It definitely is a stack-not-refcounted problem. The warning tells you that you are subject to undefined behaviour: that could mean a crash or having your hard disk formatted, as well as just getting the wrong answer. The warning is telling you that the code needs changing, at least for any perl that isn't refcounting stack items.

        2) If you change your code to iterate over the keys, then you can check whether the value exists by the time you come to process it, and take whatever avoiding action is appropriate:

        my $hr1 = {}; my $hr2 = {}; my $hr3 = {"$hr1" => $hr1, "$hr2" => $hr2}; my @values = sort values %$hr3; print "@values\n"; my (@arr); foreach my $k (sort { $hr3->{$a} cmp $hr3->{$b} } keys %$hr3) { unless (exists $hr3->{$k}) { warn "key '$k' deleted during loop\n"; next; } my $v = $hr3->{$k}; print "$v\n"; delete $hr3->{$values[1]}; push @arr, "hello"; } HASH(0x560669c681e0) HASH(0x560669c683c0) HASH(0x560669c681e0) key 'HASH(0x560669c683c0)' deleted during loop
        That seems like a good feature instead of a problem.

        dave_the_m has done (and continues to do) quite a bit of work on refcounting the stack.
        You can check on the progress by building blead with the -DPERL_RC_STACK added to ccflags.
        IIRC, on linux builds, just add -Accflags=-DPERL_RC_STACK to the Configure args.
        Here's a simple demo of the issue, posted a while back by Dave (on the p5p mailing list, I think):
        @a = qw(aaa bbb); f(@a); sub f { # on entry, $_[0] is an alias of $a[0], # $_[1] is an alias of $a[1], print "@_\n"; # correctly prints "aaa bbb" @a = (); # this prematurely frees $_[0] and $_[1] # this causes the two just-freed SVs to be reallocated my $x = 'xxx:yyy'; my @x = split /:/, $x; # but the two reallocated SVs are still referenced by @_ print "@_\n"; # incorrectly prints "xxx yyy" }
        Four months back, I built the then-current devel release (perl-5.39.3) with that flag added - just curious to see whether it did something it shouldn't be doing on Windows. (It was fine, of course.)
        It fixed that particular demo. The script output became:
        aaa bbb aaa bbb
        But there are still other aspects of the issue to be addressed, upon which Dave continues to work.

        Cheers,
        Rob