Skip Menu |

This queue is for tickets about the Class-Singleton CPAN distribution.

Report information
The Basics
Id: 68526
Status: resolved
Priority: 0/
Queue: Class-Singleton

People
Owner: Nobody in particular
Requestors: shay [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 1.4
Fixed in: (no value)



Subject: Singleton objects are not always destroyed properly
The attached program is a greatly simplified version of a problem that I've been having in which Class::Singleton objects are not always destroyed as I would expect. The program creates the instance of the singleton class called One, giving it an attribute called attr which is an instance of a simple class called Attr, and then exits, at which point the singleton object will be destroyed. The problem is that although the DESTROY method of One does indeed get called at the expected time (just after the END subroutine of One has been called), the object that it is destroying seems to have been partially destroyed already: the attr attribute is now the undefined value, rather than the Attr object. The output from the program shows this: RUNNING: attr => Attr=HASH(0x1839a68) OK EXITING ENDING: attr => Attr=HASH(0x1839a68) DESTROYING: attr => <undef> showing that the Attr was still there when One's END subroutine was entered, but is gone by the time One's DESTROY method is entered. In my real software this is a problem because One's DESTROY method actually needs to do something with Attr before setting it to the undefined value itself. The strange thing is that it seems rather unpredictable whether Attr will be there or not. For example, if I change the line: $a = One->instance(attr => Attr->new()); to: $a = One->instance(); $a->{attr} = Attr->new(); then the output is now: RUNNING: attr => Attr=HASH(0x1839af8) OK EXITING ENDING: attr => Attr=HASH(0x1839af8) DESTROYING: attr => Attr=HASH(0x1839af8) showing that the Attr is still there this time! I don't understand how that change can have made any difference. And if I now additionally override _new_instance() in One with this simple method which just delegates to the base class method: sub _new_instance { shift->SUPER::_new_instance(@_); } then the output is now: RUNNING: attr => Attr=HASH(0x18464f8) OK EXITING ENDING: attr => Attr=HASH(0x18464f8) DESTROYING: attr => <undef> once again! Again, I don't understand how that change can have made that difference. Is this actually an issue with perl, rather than Class::Singleton? Perhaps the order in which it cleans up different packages and the variables in them is dependent to some extent on what's been loaded where in memory, or maybe it's walking through a hash, whose key/value pairs are returned in seemingly random orders which are affected by the insertion of new subroutines into symbol tables etc?... Either way, I find the result is that Class::Singleton objects are not always ideal to work with, and if anything can be done to make the destruction of these objects behave in a more predictable manner then that would be a great help. This problem may be related to the trouble reported on CPAN RT #23568. I haven't yet checked whether using the patch from that bug report would solve the problem, but it does seem like Class::Singleton taking explicit steps to clean up objects derived from it, rather than leaving everything to the perils of later "automatic" clean up, might be the answer.
Subject: test.pl
use strict; use warnings; package Attr; sub new { bless {}, shift } package One; use parent qw(Class::Singleton); sub DESTROY { print "DESTROYING: attr => ", (shift->{attr} // '<undef>'), "\n"; } sub END { if (my $a = One->has_instance()) { print "ENDING: attr => ", ($a->{attr} // '<undef>'), "\n"; } else { print "ENDING: No instance\n"; } } package main; my $a; { if (eval { local $SIG{__DIE__}; $a = One->instance(attr => Attr->new()); print "RUNNING: attr => ", ($a->{attr} // '<undef>'), "\n"; 1; }) { print "OK\n"; } else { print "ERROR: $@"; } } print "EXITING\n";
I've been testing this some more with different versions of perl (5.16.1 and 5.21.0) and it is still a problem. It surely boils down to the unpredictable order of destruction of objects during the global destruction phase when perl shuts down at the end of a program. With different versions of perl I get different results, but with both versions there is always some permutation of the changes to the original test program that I pointed out in my original bug report that doesn't work "correctly". I have also now tested with the patch from #23568 and that does indeed fix the problem by making the order of destruction more predictable. All permutations of the test script now work correctly with both versions of perl. So please can you release a new version of Class-Singleton with this problem fixed? (If you aren't maintaining it any more then I will very gladly take it over and do the honours myself.)
Subject: Re: [rt.cpan.org #68526] Singleton objects are not always destroyed properly
Date: Fri, 07 Nov 2014 12:57:33 +0000
To: bug-Class-Singleton [...] rt.cpan.org
From: Andy Wardley <abw [...] wardley.org>
On 07/11/2014 09:09, Steve Hay via RT wrote: Show quoted text
> (If you aren't maintaining it any more then I will very gladly take it over and do the honours myself.)
Hi Steve, Many thanks for your efforts. Unfortunately I don't have the time to give it the proper attention it deserves, so I'll gladly take you up on your offer. I've added you as a co-maintainer of the module so you should be good to go. All the best Andy
On Fri Nov 07 07:57:44 2014, abw@wardley.org wrote: Show quoted text
> On 07/11/2014 09:09, Steve Hay via RT wrote:
> > (If you aren't maintaining it any more then I will very gladly take > > it over and do the honours myself.)
> > Hi Steve, > > Many thanks for your efforts. Unfortunately I don't have the time to > give it the proper attention it deserves, so I'll gladly take you up > on > your offer. I've added you as a co-maintainer of the module so you > should be good to go. > > All the best > Andy
Thanks, Andy. I've just uploaded version 1.5 which has this problem fixed now :-)