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?
source to share
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.
source to share
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.
source to share