Perl die() 调用神秘地没有死

Posted

技术标签:

【中文标题】Perl die() 调用神秘地没有死【英文标题】:Perl die() call mysteriously not dying 【发布时间】:2020-12-03 23:35:22 【问题描述】:

在对项目中的一个非常模糊的错误进行了一些认真的调试之后,我能够得到这个简短的代码。没有死亡的死亡召唤。

该问题仅在调用 script.pl 时发生。如果直接调用Class_A,则die调用成功。

我们需要三个文件:

文件 1:script.pl

use strict;
use warnings;
use lib '.';
use Class_A;

# This should not execute. Class_A should die at loading time
print "We shouldn't get here. Class_A shoud not load and die.\n";

文件 2:Class_A.pm

package Class_A;
use strict;
use warnings;
use Class_B;

# This code SHOULD die:
my $p = Class_B->new;
$p->do_something->die_now;


1;

文件 3:Class_B.pm

package Class_B;
use strict;
use warnings;

sub new 
    my $class = shift;
    bless , $class;


sub do_something 
    my $self = shift;


sub die_now 
    die "No soup for you!";


sub DESTROY 
    eval 
        1;
    ;


1;

注意到链接调用at Class_A.pm line 8了吗?好吧,如果你解开它,那么代码就会成功终止。 :-|

# This works. There should be no difference.
$p->do_something;
$p->die_now;

而且,最后的惊喜是发现只需删除 eval 调用 at Class_B.pm line 19,然后事情就会按预期运行,脚本就会终止。

我有机会在Perl 5.22.2Perl 5.26.1Perl 5.32.0 中对此进行了测试。另一个惊喜是,这个问题不仅仅发生在 5.32.0 上。

说真的,WT*?对这里发生的事情有什么想法吗?

【问题讨论】:

有趣!我不确定根本原因,但是 eval 上的 perldoc 页面有这样一个小声明:“它 [eval] 也是 Perl 的异常捕获机制,其中 die 运算符用于引发异常。”。似乎 Die+Destructor+Eval 的组合变得混乱了......就像来自 Die 的 eval 与 Destroy 中的 eval 的嵌套可能有问题。 你忘了把它和链式调用混在一起,因为如果没有链式,那么一切都很好。 提示:. 不是脚本的目录。使用use FindBin qw( $RealBin ); use lib $RealBin; 【参考方案1】:

您发布的代码自 5.28 以来未出现此问题。

该问题与由于异常而发生的展开期间$@ 被破坏(使用eval )有关。显然,取消设置 $@ 会使 Perl 误以为没有发生异常。

根据 perl528delta,$@ 现在在所有内容被销毁后设置,这可以防止析构函数破坏 $@。您还可以通过添加 local $@; 来防止析构函数破坏 $@(例如,支持旧版本的 Perl)。

【讨论】:

有趣。关于为什么它发生在链式调用中的任何想法,而不是通过解链它? Eval 仍在同一时间做同样的事情。 与堆栈上的变量何时被释放有关。

以上是关于Perl die() 调用神秘地没有死的主要内容,如果未能解决你的问题,请参考以下文章

`死`时如何告诉行号?

Perl:使用 gzip 打开不存在的 gz 文件时,`die` 不起作用

perl 5 鲤鱼的 raku 类似物是啥?

Perl 内置退出并在一个命令中打印

perl eval "...propagated" 记录在哪里

macos shell脚本不返回控制