简体   繁体   English

如何覆盖 Perl eval 块中的 exit() 调用

[英]How to override exit() call in Perl eval block

I need to eval some code in Perl that might some times contain an exit() call in it.我需要在 Perl 中eval一些代码,这些代码有时可能包含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 exit() call.因为exit()调用。

I tried setting some keys in %SIG (QUIT, STOP, TERM, BREAK, etc) but that didn't work.我尝试在%SIG设置一些键(QUIT、STOP、TERM、BREAK 等),但是没有用。 I also attempted to redefine CORE::exit with no success.我还尝试重新定义CORE::exit ,但没有成功。

How can I prevent an exit() call from being effective when being eval ed?eval ed 时如何防止exit()调用生效?

You can override exit , but you must do so at compile-time.您可以覆盖exit ,但您必须在编译时这样做。 So use a flag to signal whether the 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();
};

my $exit_was_called = $@ eq "EXIT_OVERRIDE\n";
die $@ if $@ && !$exit_was_called;

die("Exit called\n") if $exit_was_called;

But that creates an exception that might be caught unintentionally.但这会创建一个可能无意中捕获的异常。 So let's use last instead.所以让我们用last代替。

our $override_exit = 0;
BEGIN { 
   *CORE::GLOBAL::exit = sub(;$) {
      no warnings qw( 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() };
   die $@ if $@;
   $exit_was_called = 0;
}

die("Exit called\n") if $exit_was_called;

Note that eval BLOCK is used to catch exception.请注意, eval BLOCK用于捕获异常。 eval EXPR is used to compile code. eval EXPR用于编译代码。

exit isn't meant to be trapped, so eval isn't the solution here. exit并不意味着被困,所以eval不是这里的解决方案。 You could put the remaining code you need to run in an END 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, positively need to prevent exit from killing the script, you'll have to redefine exit() at compile time:但是,如果您绝对需要防止exit杀死脚本,则必须在编译时重新定义exit()

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 the CPAN can be used to encapsulate this bit of ugliness for you, if you're interested in a more robust solution.如果您对更健壮的解决方案感兴趣,可以使用 CPAN 中的 Test::Trap 模块为您封装这种丑陋之处。 Personally I would locally patch the exit ing some_function() to use croak instead, and maybe file a bug report with the patch if it's a module.就我个人而言,我会在本地修补some_function()exit以使用croak ,并且如果它是一个模块,可能会随补丁一起提交错误报告。

If you're just eval ing user input and you don't want them to be able to call exit , verify that the string contains no calls to exit or to a subroutine that would indirectly exit, then eval it.如果您只是eval用户输入并且您不希望他们能够调用exit ,请验证该字符串不包含对exit或间接退出的子例程的调用,然后对其进行eval Personally I'd be more afraid of unlink and fork than exit if the user is inputting arbitrary code to be evaluated.就个人而言,如果用户输入要评估的任意代码,我会更害怕unlinkfork不是exit

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM