为什么`$ @`不可信? [英] Why is `$@` untrustworthy?

查看:137
本文介绍了为什么`$ @`不可信?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎记得,在 eval 之后,信任 $ @ 的价值是不安全的。有一个信号处理程序有机会在看到它或某事之前设置 $ @ 。我现在也太累了,懒得跟踪真正的原因。所以,为什么不信任 $ @

解决方案

Try :: Tiny


eval有一些问题。



Clobbering $ @



当您运行eval块并且成功时,$ @将被清除,可能会导致目前正在被捕获的错误。



这会导致一段距离的操作,清除以前的



$ @必须在调用eval之前进行正确的本地化才能避免此问题。



更具体地说,$ @在eval的开始被破坏,这也使得在死之前无法捕获以前的错误(例如,当制作异常对象w第i个错误堆栈)。



为此,尝试将在$块的开头设置$ @为其先前的值(在本地化之前)。



本地化$ @默认屏蔽错误



在一个eval块中,die的行为类似于: / p>

  sub die {
$ @ = $ _ [0];
return_undef_from_eval();
}

这意味着如果你有礼貌和本地化的$ @你不能死在该范围内,或者您的错误将被丢弃(打印出现错误)。



解决方法非常难看:

 我的$ error = do {
local $ @;
eval {...};
$ @;
};

...
死$错误;

$ @可能不是真实值



此代码错误:

  if($ @){
.. 。
}

因为以前的注意事项,可能是未设置的。 >

$ @也可以是一个重载的错误对象,评估为false,但这是要求麻烦。



经典失败模式是:

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

eval {
my $ obj = Object-> new;

diefoo;
};

如果($ @){

}



<在这种情况下,由于Object :: DESTROY不是本地化$ @但仍然使用eval,所以将$ @设置为。



当析构函数被调用时堆栈解开后,将$ @设置为foo at Foo.pm line 42\\\
,所以在if($ @)被评估的时候,它已经被析构函数中的eval清除了。



解决方法比以前更容易。即使我们无法从不本地化的代码中保存$ @的值,我们至少可以确定由于错误而使eval被中止:

 我的$ failed = not eval {
...

return 1;
};

这是因为捕获死亡的eval将始终返回false值。



I seem to recall that it is not safe to trust the value of $@ after an eval. Something about a signal handler having a chance to set $@ before you see it or something. I am also too tired and lazy right now to track down the real reason. So, why is it not safe to trust $@?

The Try::Tiny perldoc has the definitive discussion of the trouble with $@:

There are a number of issues with eval.

Clobbering $@

When you run an eval block and it succeeds, $@ will be cleared, potentially clobbering an error that is currently being caught.

This causes action at a distance, clearing previous errors your caller may have not yet handled.

$@ must be properly localized before invoking eval in order to avoid this issue.

More specifically, $@ is clobbered at the beginning of the eval, which also makes it impossible to capture the previous error before you die (for instance when making exception objects with error stacks).

For this reason try will actually set $@ to its previous value (before the localization) in the beginning of the eval block.

Localizing $@ silently masks errors

Inside an eval block die behaves sort of like:

sub die {
        $@ = $_[0];
        return_undef_from_eval();
}

This means that if you were polite and localized $@ you can't die in that scope, or your error will be discarded (printing "Something's wrong" instead).

The workaround is very ugly:

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

...
die $error;

$@ might not be a true value

This code is wrong:

if ( $@ ) {
        ...
}

because due to the previous caveats it may have been unset.

$@ could also be an overloaded error object that evaluates to false, but that's asking for trouble anyway.

The classic failure mode is:

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

eval {
        my $obj = Object->new;

        die "foo";
};

if ( $@ ) {

}

In this case since Object::DESTROY is not localizing $@ but still uses eval, it will set $@ to "".

The destructor is called when the stack is unwound, after die sets $@ to "foo at Foo.pm line 42\n", so by the time if ( $@ ) is evaluated it has been cleared by eval in the destructor.

The workaround for this is even uglier than the previous ones. Even though we can't save the value of $@ from code that doesn't localize, we can at least be sure the eval was aborted due to an error:

my $failed = not eval {
        ...

        return 1;
};

This is because an eval that caught a die will always return a false value.

这篇关于为什么`$ @`不可信?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆