Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

perl overload concatenation operator (".") problem

Tags:

perl

Please, help me to understand, why reference count is growth on each concatenation? I am returning the same object in overloaded sub, and expecting, that refcount will stay untouched. But, seems, that perl cloning and storing object somewhere every time. Why and how I can avoid this?

Also, I am expecting, that object will be destroyed just after exiting scope, but due to non-zero references count it destroyed only on global destruction phase. This is looks like a memory leak.

#!/usr/bin/env perl

use strict;
use warnings;
use Devel::Refcount qw[refcount];

package AAA {
    use Devel::Refcount qw[refcount];

    use overload
      '.' => sub {
        print 'CONCAT, REFCOUNT: ', refcount( $_[0] ), "\n";

        # return AAA->new;
        return $_[0];
      },
      fallback => 0;

    sub new { return bless {}, $_[0] }

    sub DESTROY { print "DESTROY\n" }
}

print "--- start\n";

{
    my $o = AAA->new;

    my $s = '1' . ( '2' . ( '3' . ( '4' . ( '5' . $o ) ) ) );

    print "--- exit scope\n";
    print 'REFCOUNT: ', refcount($o), "\n";
}

print "--- end\n";

1;

Tested under

  • perl 5.28.1 x64
  • Devel::Refcount 0.10
  • overload 1.30

Output

--- start
CONCAT, REFCOUNT: 1
CONCAT, REFCOUNT: 3
CONCAT, REFCOUNT: 5
CONCAT, REFCOUNT: 7
CONCAT, REFCOUNT: 9
--- exit scope
REFCOUNT: 6
--- end
DESTROY
like image 849
zdm Avatar asked Jan 22 '19 08:01

zdm


1 Answers

Just like the delayed DESTROY message, adding a weak ref to the object indicates a leak. The leak appears to have been introduced in Perl 5.28.

use strict;
use warnings;
use Scalar::Util qw( weaken );

package AAA {
    use overload
        '.' => sub { $_[0] },
        fallback => 0;

    sub new { return bless {}, $_[0] }

    sub DESTROY { print "DESTROY\n" }
}

my $w;
{
    my $o = AAA->new;
    weaken($w = $o);
    my $s = '1' . ( '2' . ( '3' . ( '4' . ( '5' . $o ) ) ) );
    print "Exiting scope...\n";
}

print "leak!\n" if defined($w);
#use Devel::Peek;
#Dump($w);

print "Global destruction...\n";

Output (before 5.28):

Exiting scope...
DESTROY
Global destruction...

Output (5.28.0 and 5.28.1):

Exiting scope...
leak!
Global destruction...
DESTROY

Please report using the perlbug command line utility.
The bug report can be found here.
It has been fixed in 5.30. It might be fixed in 5.28.2.

like image 133
ikegami Avatar answered Nov 01 '22 10:11

ikegami