Perl die调用神秘地死了

问题描述

@H_502_0@在进行了一些认真的调试工作之后,我发现了这个简短的代码,并且该项目中的一个非常模糊的错误。没死的死话。

@H_502_0@仅当调用script.pl时才会发生此问题。如果直接呼叫Class_A,则die呼叫将成功。

@H_502_0@我们需要三个文件

@H_502_0@ 文件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";
@H_502_0@ 文件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;
@H_502_0@ 文件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;
@H_502_0@注意到链式呼叫at Class_A.pm line 8吗?好吧,如果您取消链接,那么代码将成功终止。 :-|

# This works. There should be no difference.
$p->do_something;
$p->die_Now;
@H_502_0@最后,令人惊讶的是发现仅通过删除eval调用 at Class_B.pm line 19,事情就按预期运行并且脚本消失了。

@H_502_0@我有机会在Perl 5.22.2Perl 5.26.1Perl 5.32.0中对此进行了测试。另一个令人惊奇的是,此问题不仅发生在5.32.0上。

@H_502_0@严重,WT *?对这里发生的事情有什么想法吗?

解决方法

您发布的代码从5.28开始没有出现问题。

问题与$@在因异常而发生的展开过程中(使用eval { })遭到破坏有关。显然,取消设置$@会使Perl认为没有异常发生。

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