如何在Perl eval块中重写exit()调用

如何在Perl eval块中重写exit()调用,perl,eval,Perl,Eval,我需要eval一些Perl代码,这些代码有时可能包含exit()调用。一个非常简单的例子是: use strict; use warnings; eval "some_function()"; die $@ if $@; print "Still alive!\n"; sub some_function { print "Hello from some_function\n"; exit; } 因为调用了exit(),所以我从来没有听到过“还活着!” 我尝试在%SIG

我需要
eval
一些Perl代码,这些代码有时可能包含
exit()
调用。一个非常简单的例子是:

use strict;
use warnings;


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

print "Still alive!\n";


sub some_function {
    print "Hello from some_function\n";
    exit;
}
因为调用了
exit()
,所以我从来没有听到过“还活着!”

我尝试在
%SIG
中设置一些键(退出、停止、终止、中断等),但没有成功。我还试图重新定义
CORE::exit
,但没有成功


如何防止
exit()
调用在执行
eval
ed时生效?
exit
并不意味着被捕获,因此
eval
不是解决方案。您可以将需要运行的剩余代码放在
END
块中:

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

sub some_function {
    print "Hello from some_function\n";
    exit;
}
但是,如果您确实需要防止
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 }
如果您对更健壮的解决方案感兴趣,可以使用CPAN中的Test::Trap模块来封装这一点。就我个人而言,我会在本地修补
exit
ing
some_function()
以使用
croak
,如果它是一个模块,我可能会用修补程序提交错误报告


如果您只是
eval
ing用户输入,并且您不希望他们能够调用
exit
,请验证该字符串不包含对
exit
或将间接退出的子例程的调用,然后
eval
it。就我个人而言,如果用户输入任意代码进行评估,我更担心
取消链接
分叉
,而不是
退出

您可以覆盖
退出
,但必须在编译时这样做。因此,使用一个标志来表示超越是否处于活动状态

我们的$override\u exit=0;
开始{
*核心::全局::退出=子(;$){
如果$OVERRIDE\u EXIT,则禁用“EXIT\u OVERRIDE\n”;
CORE::exit($\u0]//0);
};
}
评估{
本地$override_exit=1;
一些函数();
};
我的$exit\u被调用=$@eq“exit\u覆盖\n”;
死$@如果$@&$出口被称为出口;
如果调用了$Exit\u,则为die(“调用Exit\n”);
但这会创建一个可能被无意中捕获的异常。因此,让我们使用
last

我们的$override\u exit=0;
开始{
*核心::全局::退出=子(;$){
无警告qw(退出);
如果$OVERRIDE\u EXIT,则上次退出\u OVERRIDE;
CORE::exit($\u0]//0);
};
}
我的$exit_被称为=1;
退出超控:{
本地$override_exit=1;
eval{some_function()};
死亡$@如果$@;
$exit_被调用=0;
}
如果调用了$Exit\u,则为die(“调用Exit\n”);


请注意,
eval块
用于捕获异常<代码>eval EXPR用于编译代码。

非常好,再次感谢。:-)因此,如果evaled代码显式调用
CORE::exit
,我想我将无法阻止它。对吗?我想,您必须安装一个操作码检查器来更改
exit
操作码的ppaddr。