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

"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.

Replies are listed 'Best First'.
Re^8: Use of freed value in iteration
by hv (Prior) on Feb 13, 2024 at 17:21 UTC

    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
Re^8: Use of freed value in iteration
by syphilis (Archbishop) on Feb 14, 2024 at 00:11 UTC
    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
      It fixed that particular demo. The script output became: aaa bbb aaa bbb
      If $_[0] is supposed to be an alias of $a[0] and $_[1] an alias of $a[ +1], I'm not sure I'd want that second print "@_\n" to print aaa bbb.

      At least in a loop, if an object has been deleted I'd want that to be noticed when trying to access it. It seems like the desirable behavior, regardless of what the refcount is doing, would be for 1) deleted values occurring within the loop to be reflected if those values are accessed, but 2) the memory occupied by those values couldn't be reused by a different object during the loop. This may be desirable for the subroutine behavior also.

        I'm not sure I'd want that second print "@_\n" to print aaa bbb.
        I'd want it to. Consider this:
        my @a = qw(aaa bbb); my $r = \$a[0]; @a = (); print $$r;
        I'd expect that to print "aaa". This is pretty much at the heart of the reference-counting model at the heart of perl. Similarly to how the fact that the lexical var getting freed on scope exit doesn't free the return value in:
        sub f { my $x = ...; return $x }

        Dave.