问题描述
在进行了一些认真的调试工作之后,我发现了这个简短的代码,并且该项目中的一个非常模糊的错误。没死的死话。
仅当调用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.1
和Perl 5.32.0
中对此进行了测试。另一个令人惊奇的是,此问题不仅发生在5.32.0
上。
严重,WT *?对这里发生的事情有什么想法吗?
解决方法
您发布的代码从5.28开始没有出现问题。
问题与$@
在因异常而发生的展开过程中(使用eval { }
)遭到破坏有关。显然,取消设置$@
会使Perl认为没有异常发生。
根据perl528delta,现在$@
被设置为在所有内容都销毁之后设置,这可以防止析构函数破坏$@
。您还可以通过添加$@
来防止析构函数破坏local $@;
(例如,以支持Perl的较早版本)。