为什么`$ @`不值得信任?

Cha*_*ens 12 perl eval exception race-condition

我似乎记得,相信之后的价值是不安全$@eval.关于信号处理程序$@在你看到它之前有机会设置的东西.我现在也太累了,懒得追查真正的原因.那么,为什么信任不安全$@呢?

mob*_*mob 17

Try::Tiny的perldoc有麻烦的最终讨论$@:

eval存在许多问题.

Clobbering $ @

当你运行一个eval块并且它成功时,$ @将被清除,可能会破坏当前被捕获的错误.

这会导致远程操作,清除调用者可能尚未处理的先前错误.

在调用eval之前,$ @必须正确本地化,以避免此问题.

更具体地说,$ @在eval的开头被破坏了,这也使得在你死之前无法捕获先前的错误(例如在制作具有错误堆栈的异常对象时).

出于这个原因,try实际上会将$ @设置为eval块开头的前一个值(在本地化之前).

本地化$ @静默掩盖错误

在eval块内部,模具的行为类似于:

sub die {
        $@ = $_[0];
        return_undef_from_eval();
}
Run Code Online (Sandbox Code Playgroud)

这意味着,如果你是礼貌和本地化的$ @,你不能死在那个范围,否则你的错误将被丢弃(打印"Something's wrong").

解决方法非常难看:

my $error = do {
        local $@;
        eval { ... };
        $@;
};

...
die $error;
Run Code Online (Sandbox Code Playgroud)

$ @可能不是真正的价值

这段代码错了:

if ( $@ ) {
        ...
}
Run Code Online (Sandbox Code Playgroud)

因为之前的警告可能是未设置的.

$ @也可能是一个评估为false的重载错误对象,但无论如何都要求麻烦.

经典的失败模式是:

sub Object::DESTROY {
        eval { ... }
}

eval {
        my $obj = Object->new;

        die "foo";
};

if ( $@ ) {

}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,由于Object :: DESTROY没有本地化$ @但仍然使用eval,它将$ @设置为"".

在堆栈展开后调用析构函数,在模具将$ @设置为"Foo.pm第42行\n"后的foo,因此在if($ @)被计算的时候,它已被析构函数中的eval清除.

对此的解决方法甚至比以前更加困难.即使我们无法从未本地化的代码中保存$ @的值,我们至少可以确保eval因错误而中止:

my $failed = not eval {
        ...

        return 1;
};
Run Code Online (Sandbox Code Playgroud)

这是因为捕获骰子的eval将始终返回false值.

  • 不必再玩这些疯狂的游戏了. (2认同)

raf*_*afl 13

尝试::微小的文档有一个很好的列表eval/ $@缺点.我想你可能会在那里引用Localizing $ @ silentntly mask errors部分.


bri*_*foy 7

$@具有与每个全局变量相同的问题:当其他东西设置它时,它会在整个程序中重置.任何eval可能的设定$@.即使你没有看到eval附近,你也不知道还有谁可以调用它(子程序,绑定变量等).