Perl die调用神秘地死了

问题描述

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

仅当调用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 *?对这里发生的事情有什么想法吗?

解决方法

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

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

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

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...