Cha*_*ens 12 perl eval exception race-condition
我似乎记得,相信之后的价值是不安全$@的eval.关于信号处理程序$@在你看到它之前有机会设置的东西.我现在也太累了,懒得追查真正的原因.那么,为什么信任不安全$@呢?
mob*_*mob 17
该Try::Tiny的perldoc有麻烦的最终讨论$@:
eval存在许多问题.
Clobbering $ @
当你运行一个eval块并且它成功时,$ @将被清除,可能会破坏当前被捕获的错误.
这会导致远程操作,清除调用者可能尚未处理的先前错误.
在调用eval之前,$ @必须正确本地化,以避免此问题.
更具体地说,$ @在eval的开头被破坏了,这也使得在你死之前无法捕获先前的错误(例如在制作具有错误堆栈的异常对象时).
出于这个原因,try实际上会将$ @设置为eval块开头的前一个值(在本地化之前).
本地化$ @静默掩盖错误
在eval块内部,模具的行为类似于:
Run Code Online (Sandbox Code Playgroud)sub die { $@ = $_[0]; return_undef_from_eval(); }这意味着,如果你是礼貌和本地化的$ @,你不能死在那个范围,否则你的错误将被丢弃(打印"Something's wrong").
解决方法非常难看:
Run Code Online (Sandbox Code Playgroud)my $error = do { local $@; eval { ... }; $@; }; ... die $error;$ @可能不是真正的价值
这段代码错了:
Run Code Online (Sandbox Code Playgroud)if ( $@ ) { ... }因为之前的警告可能是未设置的.
$ @也可能是一个评估为false的重载错误对象,但无论如何都要求麻烦.
经典的失败模式是:
Run Code Online (Sandbox Code Playgroud)sub Object::DESTROY { eval { ... } } eval { my $obj = Object->new; die "foo"; }; if ( $@ ) { }在这种情况下,由于Object :: DESTROY没有本地化$ @但仍然使用eval,它将$ @设置为"".
在堆栈展开后调用析构函数,在模具将$ @设置为"Foo.pm第42行\n"后的foo,因此在if($ @)被计算的时候,它已被析构函数中的eval清除.
对此的解决方法甚至比以前更加困难.即使我们无法从未本地化的代码中保存$ @的值,我们至少可以确保eval因错误而中止:
Run Code Online (Sandbox Code Playgroud)my $failed = not eval { ... return 1; };这是因为捕获骰子的eval将始终返回false值.
$@具有与每个全局变量相同的问题:当其他东西设置它时,它会在整个程序中重置.任何eval可能的设定$@.即使你没有看到eval附近,你也不知道还有谁可以调用它(子程序,绑定变量等).
| 归档时间: |
|
| 查看次数: |
1055 次 |
| 最近记录: |