Perl 为什么“$@”不值得信任?
我似乎记得,在进行Perl 为什么“$@”不值得信任?,perl,exception,eval,race-condition,Perl,Exception,Eval,Race Condition,我似乎记得,在进行评估后,信任$@的值是不安全的。信号处理程序在您看到它或其他东西之前有机会设置$@。我现在也太累太懒了,找不到真正的原因。那么,为什么信任$@。我想你可能是在参考那里的章节。perldoc对$@的问题进行了明确的讨论: eval有许多问题 Clobbering$@ 当运行eval块并成功时,$@将被清除,可能会导致当前捕获的错误 这将导致远程操作,清除调用方可能尚未处理的先前错误 在调用eval之前,必须正确本地化$@以避免此问题 更具体地说,$@在评估开始时被删除,这也使得您
评估后,信任$@
的值是不安全的。信号处理程序在您看到它或其他东西之前有机会设置$@
。我现在也太累太懒了,找不到真正的原因。那么,为什么信任$@
。我想你可能是在参考那里的章节。perldoc对$@
的问题进行了明确的讨论:
eval有许多问题
Clobbering$@
当运行eval块并成功时,$@将被清除,可能会导致当前捕获的错误
这将导致远程操作,清除调用方可能尚未处理的先前错误
在调用eval之前,必须正确本地化$@以避免此问题
更具体地说,$@在评估开始时被删除,这也使得您无法在死之前捕获上一个错误(例如,在创建带有错误堆栈的异常对象时)
因此,try实际上会在eval块的开头将$@设置为其先前的值(在本地化之前)
本地化$@会隐藏错误
在评估块内部,模具的行为类似于:
sub die {
$@ = $_[0];
return_undef_from_eval();
}
这意味着,如果你是有礼貌的,并且本地化了$@你就不能在这个范围内死亡,否则你的错误将被丢弃(而是打印“有问题”)
解决方法非常难看:
my $error = do {
local $@;
eval { ... };
$@;
};
...
die $error;
$@可能不是真实值
此代码错误:
if ( $@ ) {
...
}
因为由于之前的警告,它可能已经被取消
$@也可能是一个重载的错误对象,其计算结果为false,但这会带来麻烦
典型的故障模式是:
sub Object::DESTROY {
eval { ... }
}
eval {
my $obj = Object->new;
die "foo";
};
if ( $@ ) {
}
在这种情况下,由于Object::DESTROY未本地化$@但仍使用eval,因此它将$@设置为“”
当堆栈展开时,在模具将$@设置为“foo at foo.pm line 42\n”后调用析构函数,因此在计算($@)时,析构函数中的eval已将其清除
解决这一问题的方法甚至比以前的方法更糟糕。即使我们无法从未本地化的代码中保存$@的值,我们至少可以确保由于错误而中止了评估:
my $failed = not eval {
...
return 1;
};
这是因为捕捉到骰子的eval总是返回一个假值
$@
与每个全局变量都有相同的问题:当其他变量设置它时,它会在整个程序中重置。任何eval
都可能设置$@
。即使你在附近看不到eval
,你也不知道还有谁会调用它(子程序、绑定变量等等)。另请注意,作为Perl 5.14,是的,我想这就是我记得的。不要再玩那些疯狂的游戏了。