Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Journal of IlyaM (2933)

Monday March 03, 2003
05:52 AM

Nasty side-effects of Exception::Class

[ #10859 ]
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');

sub test {
    MyException->throw(error => 'Test');
}

eval {
    my $x = bless {}, 'X';
    test($x);
};
if($@) {
    print 2;
}

sub X::DESTROY {
    print 1;
}

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?

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • He discovered a very similiar thing with Error.pm a while back. It's documented in a set of slides [axkit.org] he did about exceptions...

    Basically, closures + exceptions are a bad thing. This needs to be documented better somewhere in Perl.

    -Dom

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

      Ilya Martynov (http://martynov.org/ [martynov.org])

  • by Matts (1087) on 2003.03.03 8:05 (#17655) Journal
    {
      local $@;
      eval {
        my $x = Object->new();
        do_something_bad($x);
      };
      if ($@) {
        ...
      }
    }
    • 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 objec

      --

      Ilya Martynov (http://martynov.org/ [martynov.org])

  • Exception::Class::Base->NoRefs(1);

    This will pass along the no_refs parameter to all Devel::StackTrace objects created, and no references will be stored.

    This should perhaps be the default, though.

    -dave