What happens if you combine a Perl module which heavily relies on Perl's garbage collector and reference counting to manage resources it creates (like POE) and exception objects created with Exception::Class? You end up with a web server which doesn't close sockets after serving a HTTP request :( It took hours to debug this problem. In essence this test case demonstrates the problem with Exception::Class:
use Exception::Class ('MyException');You would expect it to print '12' but it prints '21'. The problem is that Exception::Class stores full stack trace in exception object including all arguments passed to subs. I.e. it creates additional reference on them what means their destructors will not be called until your undefine or change $@. Any ideas how to fix/workaround it?
sub test { MyException->throw(error => 'Test'); }
eval { my $x = bless {}, 'X'; test($x); }; if($@) { print 2; }
sub X::DESTROY { print 1; }
Basically, closures + exceptions are a bad thing. This needs to be documented better somewhere in Perl.
-Dom
Re:Ask MattS
IlyaM on 2003-03-03T13:50:29
Exception::Class doesn't use closures and this problem is very different. The problem is that it stores Devel::StackTrace object in exceptions. And Devel::StackTrace references all arguments from all frames in stack trace. In this test case stack trace has a frame with call to test() sub which is passed $x variable so value of $x gets stored deeply somewhere in exception object.Re:Ask MattS
Dom2 on 2003-03-03T14:10:53
Apologies; I should have looked at the article closer.-Dom
{
local $@;
eval {
my $x = Object->new();
do_something_bad($x);
};
if ($@) {
...
}
}
Re:A quick work around...
IlyaM on 2003-03-03T13:43:59
Explicitly undefining $@ helps in my POE application but I can imaging a couple scenarious when it will not help. For example if you take my test case it still prints "21" instead of "12".Real fix is probably using weak refs to store args in stack trace or don't store store them at all. After all Exception::Class needs stack trace only to print error message for uncaught exceptions. It could just generate error message at the moment when exceptions is raised and do not store stack trace in exception objects.
Re:Ahem, it's in the docs
IlyaM on 2003-03-04T09:04:08
D'oh, I can't belive I didn't notice it in docs.Making it default is definetely good idea.