为什么“$@”不可信?

发布于 2024-09-18 06:17:16 字数 157 浏览 7 评论 0原文

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

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 $@?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

少女情怀诗 2024-09-25 06:17:16

Try::Tiny perldoc 有关于 $@ 问题的明确讨论:

eval 存在许多问题。

打击$@

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

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

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

更具体地说,$@ 在 eval 开始时被破坏,这也使得在死亡之前无法捕获先前的错误(例如,在使用错误堆栈创建异常对象时)。

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

本地化 $@ 默默地掩盖错误

在 eval 块内部,die 的行为有点像:

子模具 {
        $@ = $_[0];
        return_undef_from_eval();
}

这意味着,如果您有礼貌并且本地化 $@,您就不会死在该范围内,否则您的错误将被丢弃(改为打印“Something's error”)。

解决方法非常丑陋:

我的 $error = do {
        本地$@;
        评估{...};
        $@;
};

...
死$错误;

$@ 可能不是真实值

这段代码是错误的:

if ( $@ ) {
        ...
}

因为由于之前的警告,它可能已被取消设置。

$@ 也可能是一个重载的错误对象,其计算结果为 false,但无论如何这都是自找麻烦。

经典的故障模式是:

子对象::销毁{
        评估{...}
}

评估{
        我的 $obj = 对象->new;

        死“foo”;
};

如果($@){

}

在这种情况下,由于 Object::DESTROY 没有本地化 $@ 但仍然使用 eval,因此它将把 $@ 设置为“”。

当堆栈展开时,在 die 将 $@ 设置为“foo at Foo.pm line 42\n”之后,析构函数被调用,因此当 if ( $@ ) 被求值时,它已被 eval 中的 eval 清除。析构函数。

解决这个问题的方法比以前的方法更难看。尽管我们无法从未本地化的代码中保存 $@ 的值,但我们至少可以确定 eval 由于错误而中止:

我的 $failed = 未评估 {
        ...

        返回1;
};

这是因为捕获骰子的 eval 将始终返回错误值。

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.

少女情怀诗 2024-09-25 06:17:16

Try::Tiny 文档 有一个非常好的 列表eval/$@ 缺点。我想你可能指的是 本地化 $@ 默默地掩盖错误< /a> 部分在那里。

The Try::Tiny docs have a pretty good list of eval/$@ shortcomings. I think you might be refering to the Localizing $@ silently masks errors section in there.

北音执念 2024-09-25 06:17:16

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

$@ has the same problems that every global variable has: when something else sets it, it's reset across the entire program. Any eval might set $@. Even if you don't see an eval nearby, you don't know who else might call one (subroutines, tied variables, and so on).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文