首页 > 解决方案 > 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.2,Perl 5.26.1Perl 5.32.0. 另一个惊喜是,这个问题不仅仅发生在5.32.0

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

标签: perlevaldie

解决方案


您发布的代码自 5.28 以来没有出现问题。

该问题与由于异常而发生的展开期间$@被破坏(使用)有关。eval { }显然,令人不安的$@Perl 让 Perl 认为没有发生异常。

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


推荐阅读