How to override the exit () call in a Perl eval block

I need eval

some code in Perl that can be called multiple times exit()

. A very simplified example of this would be:

use strict;
use warnings;


eval "some_function()";
die $@ if $@;

print "Still alive!\n";


sub some_function {
    print "Hello from some_function\n";
    exit;
}

      

I never get to "Still Alive!" because of the call exit()

.

I tried to set some keys to %SIG

(QUIT, STOP, TERM, BREAK, etc.) but it didn't work. I have also tried overriding CORE::exit

without success.

How can I prevent the call from being executed exit()

when eval

ed?

+3


source to share


2 answers


You can override exit

, but you must do it at compile time. So use a flag to signal whether an override is active or not.

our $override_exit = 0;
BEGIN { 
    *CORE::GLOBAL::exit = sub (;$) {
        die "EXIT_OVERRIDE\n" if $override_exit;
        CORE::exit($_[0] // 0);
    };
 }

 eval {
    local $override_exit = 1;
    some_function();
 };

 die "Exit was called\n" if $@ eq "EXIT_OVERRIDE\n";
 die $@ if $@:

      

But this creates an exception that can be caught unintentionally. So instead of using last

.



our $override_exit = 0;
BEGIN { 
    *CORE::GLOBAL::exit = sub (;$) {
        no warnings 'exiting';
        last EXIT_OVERRIDE if $override_exit;
        CORE::exit($_[0] // 0);
    };
 }

 my $exit_was_called = 1;
 EXIT_OVERRIDE: {
    local $override_exit = 1;
    eval { some_function() };
    $exit_was_called = 0;
    die $@ if $@;
 }
 die "Exit was called\n" if $exit_was_called;

      


Please note what is eval BLOCK

used to throw exceptions. eval EXPR

used to compile code.

+7


source


exit

not meant to be captured, so is eval

not a solution here. You can put the rest of the code to run in a block END

:

some_function();
END { print "Still alive! For now...\n"; }

sub some_function {
    print "Hello from some_function\n";
    exit;
}

      

But if you absolutely need to prevent exit

the script from killing, you will have to override exit()

at compile time:



BEGIN { *CORE::GLOBAL::exit = sub (;$) { } } # Make exit() do nothing
some_function();
print "Still alive!\n"; # Gets printed

*CORE::GLOBAL::exit = *CORE::exit; # Restore exit()
exit;
print "I'm dead here.\n"; # Doesn't get printed

sub some_function { exit }

      

The Test :: Trap module from CPAN can be used to encapsulate this bit of ugliness for you if you are interested in a more robust solution. Personally, I would fix the exit

ing locally some_function()

instead, croak

and possibly the patch file if it's a module.

If you are just eval

typing user input and you do not want them to be called exit

, make sure the line does not contain calls to exit

or a subroutine that will exit indirectly, then eval

it. Personally, I would be afraid unlink

, and fork

than exit

, if the user enters an arbitrary code for evaluation.

+3


source







All Articles