Open p5pRT opened 7 years ago
This issue is believed to exist in all 5.10.1+ Perl's and every older Perl as well. I have verified the issue in every Perl I have at my disposal from 5.10.1\, 5.12.0\, 5.22.0 and 5.24.0.
Description: If the last reference to an object is in thread shared memory the objects DESTROY method won't be called or highly unlikely to be called. This is a *huge* problem for applications that are OO and designed using composition of other classes (HAS-A). The last\, and possibly only reference will be in Perl's thread shared memory. I think the real issue only resembles my description and therefore it is not perfect. I have however included a small script that when used and modified as the comments suggest the related behaviors may be observed. The actual issue is a bit more unpredictable.
## PERL BUG Example
use 5.010001; use strict; use warnings; use threads; use threads::shared;
our $VERSION = 0.1;
say 'Hello World!\, - Perl shared memory failure to call ->DESTROY detector.';
LEAKER: { ## Using the "shared" attribute can play a role in this ## Best guess it means all references are shared. my $aa :shared = bless &share({})\, 'Lazy::Crazy'; my $bb :shared = bless &share({})\, 'Lazy::Crazy'; my $cc :shared = &share( bless {}\, 'Lazy::Crazy' );
## Placing an object into another makes it a sure bet its ## ->DESTROY won't be called $aa->{ has_c } = $cc; $bb->{ has_a } = $aa;
## It's strange that the order of the following assignments ## will allow the last one touched to call its ->DESTROY $cc->{ label } = 'c'; $aa->{ label } = 'a'; $bb->{ label } = 'b';
## If I'm able to control the order these are unwrapped (destroyed) ## things start working as expected. ## How likely can I always get this right\, not at all! ## (uncomment and things work as expected) # $bb = undef; # $aa = undef; # $cc = undef; }
package Lazy::Crazy;
sub DESTROY { my $self = shift; printf "# %s '%s' is destroyed\n"\, ref $self\, $self->{ label }; return; }
## END
On Thu\, 26 Jan 2017 12:38:49 GMT\, victor.burns@bankofamerica.com wrote:
This is a bug report for Perl from victor.burns@bankofamerica.com\, generated with the help of perlbug 1.39 running under perl 5.12.2.
----------------------------------------------------------------- [Please describe your issue here]
This issue is believed to exist in all 5.10.1+ Perl's and every older Perl as well. I have verified the issue in every Perl I have at my disposal from 5.10.1\, 5.12.0\, 5.22.0 and 5.24.0.
Description: If the last reference to an object is in thread shared memory the objects DESTROY method won't be called or highly unlikely to be called. This is a *huge* problem for applications that are OO and designed using composition of other classes (HAS-A). The last\, and possibly only reference will be in Perl's thread shared memory. I think the real issue only resembles my description and therefore it is not perfect. I have however included a small script that when used and modified as the comments suggest the related behaviors may be observed. The actual issue is a bit more unpredictable.
## PERL BUG Example
use 5.010001; use strict; use warnings; use threads; use threads::shared;
our $VERSION = 0.1;
say 'Hello World!\, - Perl shared memory failure to call ->DESTROY detector.';
LEAKER: { ## Using the "shared" attribute can play a role in this ## Best guess it means all references are shared. my $aa :shared = bless &share({})\, 'Lazy::Crazy'; my $bb :shared = bless &share({})\, 'Lazy::Crazy'; my $cc :shared = &share( bless {}\, 'Lazy::Crazy' );
## Placing an object into another makes it a sure bet its ## ->DESTROY won't be called $aa->{ has_c } = $cc; $bb->{ has_a } = $aa;
## It's strange that the order of the following assignments ## will allow the last one touched to call its ->DESTROY $cc->{ label } = 'c'; $aa->{ label } = 'a'; $bb->{ label } = 'b';
## If I'm able to control the order these are unwrapped (destroyed) ## things start working as expected. ## How likely can I always get this right\, not at all! ## (uncomment and things work as expected) # $bb = undef; # $aa = undef; # $cc = undef; }
package Lazy::Crazy;
sub DESTROY { my $self = shift; printf "# %s '%s' is destroyed\n"\, ref $self\, $self->{ label }; return; }
## END
I would like to confirm the output one is supposed to get from running this program.
Running the program as submitted (which\, for convenience\, I am attaching to this RT)\, I get:
##### [threaded_blead] $ ./bin/perl -Ilib ~/learn/perl/p5p/130649-threads.pl Hello World!\, - Perl shared memory failure to call ->DESTROY detector. # Lazy::Crazy 'b' is destroyed #####
Uncommenting lines 34-36 -- the last 3 lines of the 'LEAKER' block -- and then running the program I get:
##### [threaded_blead] $ ./bin/perl -Ilib ~/learn/perl/p5p/130649-threads.pl Hello World!\, - Perl shared memory failure to call ->DESTROY detector. # Lazy::Crazy 'b' is destroyed # Lazy::Crazy 'a' is destroyed # Lazy::Crazy 'c' is destroyed #####
Is that the output you were expecting?
Thank you very much.
-- James E Keenan (jkeenan@cpan.org)
The RT System itself - Status changed from 'new' to 'open'
Yes\, when it works properly each of the constructed objects should announce its demise when the ->DESTROY method is called. When script is run as given OR modified in some of the other suggested ways the results will vary including the possibility that none of the objects will announce their demise.
Best Regards\,
Victor Burns | TG Application Architect / Developer & Perl GURU AVP\, Consultant II System Engineer\, Bank of America T 469.201.8375 | victor.burns@bankofamerica.com 16001 N Dallas Pkwy\, Addison\, TX 75001
Like us on Facebook Follow us on Twitter
Life’s better when we’re connected™
-----Original Message----- From: James E Keenan via RT [mailto:perlbug-followup@perl.org] Sent: Thursday\, January 26\, 2017 8:28 AM To: Burns\, Victor M \victor\.burns@​bankofamerica\.com Subject: [perl #130649] Threads\, shared memory\, blessed objects fail to call ->DESTROY method
I would like to confirm the output one is supposed to get from running this program.
Running the program as submitted (which\, for convenience\, I am attaching to this RT)\, I get:
##### [threaded_blead] $ ./bin/perl -Ilib ~/learn/perl/p5p/130649-threads.pl Hello World!\, - Perl shared memory failure to call ->DESTROY detector. # Lazy::Crazy 'b' is destroyed #####
Uncommenting lines 34-36 -- the last 3 lines of the 'LEAKER' block -- and then running the program I get:
##### [threaded_blead] $ ./bin/perl -Ilib ~/learn/perl/p5p/130649-threads.pl Hello World!\, - Perl shared memory failure to call ->DESTROY detector. # Lazy::Crazy 'b' is destroyed # Lazy::Crazy 'a' is destroyed # Lazy::Crazy 'c' is destroyed #####
Is that the output you were expecting?
Thank you very much.
-- James E Keenan (jkeenan@cpan.org)
This message\, and any attachments\, is for the intended recipient(s) only\, may contain information that is privileged\, confidential and/or proprietary and subject to important terms and conditions available at http://www.bankofamerica.com/emaildisclaimer. If you are not the intended recipient\, please delete this message.
The bug is that the destructor of an embedded shared object will not be called after the enclosing shared object is destroyed:
1. Create shared objects $xx and $yy. 2. Embed $yy inside $XX: $xx->{embedded} = $yy 3. Undef $yy. Its destructor is not called because it's still referenced by $xx. (This is as expected.) 4. Undef $xx. The destructor for $xx is called (as expected)\, but the destructor for $yy is not (bug).
If the above is done with ordinary objects\, the the destructors for both $xx and $yy will be called\, as expected.
One workaround is to code the destructor to actively dereference any embedded objects.
The attached code illustrates both the bug and the workaround.
The bug is that the destructor of an embedded shared object will not be called after the enclosing shared object is destroyed:
1. Create shared objects $xx and $yy. 2. Embed $yy inside $XX: $xx->{embedded} = $yy 3. Undef $yy. Its destructor is not called because it's still referenced by $xx. (This is as expected.) 4. Undef $xx. The destructor for $xx is called (as expected)\, but the destructor for $yy is not (bug).
If the above is done with ordinary objects\, the the destructors for both $xx and $yy will be called\, as expected.
One workaround is to code the destructor to actively dereference any embedded objects.
The attached code illustrates both the bug and the workaround.
Migrated from rt.perl.org#130649 (status was 'open')
Searchable as RT130649$