http://qs321.pair.com?node_id=747179

clinton has asked for the wisdom of the Perl Monks concerning the following question:

According to the perlvar docs for $SIG{__DIE__}:

Due to an implementation glitch, the $SIG{__DIE__} hook is called even inside an eval(). Do not use this to rewrite a pending exception in $@ , or as a bizarre substitute for overriding CORE::GLOBAL::die() . This strange action at a distance may be fixed in a future release so that $SIG{__DIE__} is only called if your program is about to exit, as was the original intent. Any other use is deprecated.

However, I find this particular behaviour useful. For instance, in my mod_perl application, pretty much all the code is wrapped in an eval which lets me return a nice error page to the user. Because of this glitch, I am able to inflate an uncaught exception into an error object, with attached stacktrace:

#=================================== sub uncaught_error { #=================================== die @_ if ref $_[0] # already an excep +tion object || ! defined $^S; # code is being co +mpiled my ($class) = caller(0); # throw() does the + work of inflating @_ = ( $class, 'Uncaught', join( '', @_ ) ); # an error message + into an exception object goto $class->can('throw') || \&throw; # of the relevant +class } $SIG{__DIE__} = \&uncaught_error;

Once this 'glitch' is fixed, the above code will no longer work (as in it will no longer give me a stack trace from the place where the error occurred) . Is there a better (not-about-to-be-deprecated) way to do this?

thanks

Clint

UPDATE: Added some comments to the code

Replies are listed 'Best First'.
Re: Deprecated use of $SIG{__DIE__} is useful (haste)
by tye (Sage) on Feb 28, 2009 at 19:01 UTC

    I read this about the same way I read much Perl documentation, written soon after somebody had a good idea and before much time was alotted for serious reflection on the idea. Like the prominent notice that was added to "use vars" saying that 'our' is better. Actually, there are good arguments for ways in which vars.pm is better than 'our'.

    Or documentation that "use warnings" is better than -w. perllexwarn says "use warnings" is "more flexible" than "-w" and $^W. Actually, warnings.pm is just different. It can be used to do things that can't be done with -w/$^W but it also can't do many things that can be done with -w/$^W. And I find -w and $^W to be better suited for writing modules than "use warnings" (while "use warnings" is sometimes better when writing scripts).

    There could certainly be some improvements made to how $SIG{__DIE__} handlers nest with eval and other $SIG{__DIE__} handlers, but I would be quite surprised if p5p fulfilled that ancient threat and broke Devel::EvalError and lots of other reasonable uses.

    - tye        

Re: Deprecated use of $SIG{__DIE__} is useful
by ikegami (Patriarch) on Feb 28, 2009 at 19:03 UTC

    I'm not sure of the reason for the deprecation, but how is that different from the recommended

    BEGIN { *CORE::GLOBAL::die = sub { CORE::die @_ if ref $_[0] || ! defined $^S; my ($class) = caller(0); @_ = ( $class, 'Uncaught', join( '', @_ ) ); goto $class->can('throw') || \&throw; } }

      Overriding die catches calls to die('Error'), but it doesn't catch errors such as undefined values being thrown because I've used strict.

      In situations like this, where your code behaves in an unexpected way, it is useful to have a stack trace to see how we got to that point in the code, which I can only do with $SIG{__DIE__}.

        Indeed, thanks.

        Overriding die catches calls to die('Error'), but it doesn't catch errors such as undefined values being thrown because I've used strict.

        Neither does $SIG{__DIE__}. That would be $SIG{__WARN__}.

Re: Deprecated use of $SIG{__DIE__} is useful
by perrin (Chancellor) on Feb 28, 2009 at 23:04 UTC
    The alternative would be to have a top level eval{} around your program that catches all uncaught exceptions and can apply processing like this to them.

      No, a top-level eval cannot add a stack trace. It wouldn't catch the 'die' exception until after the stack had already been unrolled.

      - tye