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,是的,我想这就是我记得的。不要再玩那些疯狂的游戏了。