0
votes

I am working with a perl framework which monitor $SIG{DIE} itself, my code was executed by the framework, so my exception handle code cannot be executed because the framework is first one to detected the exception then terminate the script.

frame.pm

sub execute
{
  $SIG{__DIE__}         = \&_handleDie;

  eval{  #execute myscript.pl sub main  
         $rv = &$pFunct(@args);}

  if ($@){ processException($@)}

  print "myscript.pl success executed"           

}

myscript.pl

use frame;
frame->execute( \&main );

sub main
{ 
   %codes that redirect STDOUT to a file% 

   #if below API cmd no exception, hide it's output, 
   #otherwise output the API cmd STDERR msg

   %codes called API of another module%


   try
    {
        die("sth wrong");
    }catch{
        %codes restore STDOUT to terminal% 
        print "error msg, but this line will not be executed, how to get it be execute?"
    }
}

The script first redirect STDOUT to a file for dumy some no use output.

When I want to implement is if exception happen(die line), the script can restore STDOUT to terminal then print error to terminal. Now it was handled by frame and print to STDOUT but not STDERR, so I need to handle restore STDOUT before frame print it to STDOUT.

with ruakh's solution, myscript.pl has passed SIG of frame, now catched by frame line if ($@){ processException($@)}, that is when execute myscript->die(), the program come to frame->if ($@){ processException($@)}, but not myscript->catch

=====================

I finally found this works for me:

myscript.pl

frame->execute( \&main );

sub main
{
    open my $stdOri, ">&STDOUT";
    my $tmpFile = "/tmp/.output.txt.$$";
    open STDOUT, ">$tmpFile";

    #overwrite frame provided exception handling.
    local $SIG{__DIE__}=sub{close STDOUT;  open STDOUT, ">&", $stdOri;};

    #cause a exception, 
    #this exception will be processed by 'local $SIG{__DIE__}' block which restore STDOUT
    #then frame->eval catch this exception, and print it in the terminal.
    my $c=5/0;

}

thanks for ruakh's inspire.

2
Re: "When I want to implement is if exception happen(die line), the script can restore STDOUT to terminal then print error to terminal": Why not just print to STDERR instead of STDOUT? Has STDERR been redirected as well? - ruakh

2 Answers

1
votes

Assuming that you don't want to modify the framework, you can locally override the signal-handler:

use frame;
frame->execute( \&main );

sub main
{
   try
    {
        local $SIG{__DIE__}; # remove signal-handler
        die("sth wrong");
    }catch{
        print STDERR "error msg";
        die $@; # pass control back to framework's signal handler
    }
}

Disclaimer: tested with an eval-block, rather than with try/catch, since I don't have TryCatch installed. My understanding is that TryCatch depends on eval, and not on $SIG{__DIE__}, but I could be wrong about that.

1
votes

The framework's $SIG{__DIE__} handler is wrong wrong wrong. It shouldn't be eating exceptions inside of an eval. It should do die @_ if $^S as suggested by perldoc -f die.