perl - 为什么 `$@` 不可信?

标签 perl exception eval race-condition

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

最佳答案

Try::Tiny perldoc 对 $@ 的问题进行了明确的讨论。 :

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.

关于perl - 为什么 `$@` 不可信?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3686857/

相关文章:

ruby - 为什么定义的输入变量在异常发生后返回nil?

grails - Grails:动态构建下拉列表时,我想评估列表的名称

python - 类型错误 : eval() arg 1 must be a string, 字节或代码对象

perl - 如何将 ctime 更改为正常的字符串表示?

python - 比较两个不同文件中的字符串的脚本

perl - 为什么 Perl 会提示 "Useless use of a constant in void context",但只是有时?

java - 在 glassfish 上部署时出现异常 : ArrayIndexOutOfBoundsException: 9578

perl - 使用独立的 Perl FastCGI/FCGI Web 服务器在 Perl 中测试 FastCGI 脚本

java - 合并两个列表

php - 数组 : set value using dot notation?