我一定让perl
非常沮丧,因为它给了我一条错误消息,该消息未在perldiag
中记录:
根据其心情,有时会出现以下情况:
...或更明确地说:
显然,这是致命的,但我也测试了它是否可捕获。使用Try::Tiny
时,我总是会在同一位置捕获该错误,但是当不使用它时,会在崩溃发生之前执行更多的指令。另外,即使我的模块是完全确定性的,并且我也可以确定所有依赖项也都可以,但是错误不会一直发生。
不幸的是,给我这个问题的模块很大,有很多依赖性,而且我还不能在一个较小的例子中重复这个问题。因此,我无法寻求帮助来调试它,但是如果熟悉Perl内部知识的人知道在哪种情况下会发生此错误,则可能会帮助我(或其他人将看到此消息)找到问题的根源和/或解决方法。
如果有用,通常的想法是这样。我有两个类,我们称它们为Thing
和SetOfThings
。 SetOfThings
具有一个属性,它是一组Thing
实例。这两个类都有一个explode
方法,该方法可以执行以下操作:
# SetOfThings
sub explode {
my $self = shift;
my $new = dclone $self;
delete $new->{'some_attribute'};
$new->set_of_things( map { $_->explode } $self->constraints );
return $new;
}
# Thing
sub explode {
my $self = shift;
return map { new Thing( do_something_fancy ) } keys %$self;
}
通常,在调用
SetOfThings::explode
或将SetOfThings::set_of_things
用作 setter/getter 时似乎会发生该错误。编辑:回溯
我不相信我有足够的能力来解释它,但是我已经从
gdb
获得了回溯:#0 0x00007ffff70a6094 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x00007ffff70a76a8 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#2 0x00007ffff70aab1c in free () from /lib/x86_64-linux-gnu/libc.so.6
#3 0x00007ffff7b0869b in Perl_hv_undef_flags () from /usr/lib/libperl.so.5.14
#4 0x00007ffff7b1ae66 in Perl_sv_clear () from /usr/lib/libperl.so.5.14
#5 0x00007ffff7b1b292 in Perl_sv_free2 () from /usr/lib/libperl.so.5.14
#6 0x00007ffff7b04bc3 in Perl_hv_free_ent () from /usr/lib/libperl.so.5.14
#7 0x00007ffff7b04e6e in ?? () from /usr/lib/libperl.so.5.14
#8 0x00007ffff7b08683 in Perl_hv_undef_flags () from /usr/lib/libperl.so.5.14
#9 0x00007ffff7b1ae66 in Perl_sv_clear () from /usr/lib/libperl.so.5.14
#10 0x00007ffff7b1b292 in Perl_sv_free2 () from /usr/lib/libperl.so.5.14
#11 0x00007ffff7b42cef in Perl_leave_scope () from /usr/lib/libperl.so.5.14
#12 0x00007ffff7b11112 in Perl_pp_leave () from /usr/lib/libperl.so.5.14
#13 0x00007ffff7b0bce6 in Perl_runops_standard () from /usr/lib/libperl.so.5.14
#14 0x00007ffff7aad815 in perl_run () from /usr/lib/libperl.so.5.14
#15 0x0000000000400f89 in main ()
编辑2:Valgrind回溯
这是我从运行
valgrind
得到的。尽管我仍然不确定发生了什么,但至少现在我知道应该归咎于谁。 :-)==27226== Invalid free() / delete / delete[] / realloc()
==27226== at 0x4C27D4E: free (vg_replace_malloc.c:427)
==27226== by 0xA138F42: PmmREFCNT_dec (in /usr/lib/perl5/auto/XML/LibXML/LibXML.so)
==27226== by 0xA11D3FA: XS_XML__LibXML__Node_DESTROY (in /usr/lib/perl5/auto/XML/LibXML/LibXML.so)
==27226== by 0x4EE770B: Perl_pp_entersub (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4E7AB90: Perl_call_sv (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4EEDBD8: Perl_sv_clear (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4EEE291: Perl_sv_free2 (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4ED7BC2: Perl_hv_free_ent (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4ED7E6D: ??? (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4EDB682: Perl_hv_undef_flags (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4EEDE65: Perl_sv_clear (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4EEE291: Perl_sv_free2 (in /usr/lib/libperl.so.5.14.2)
==27226== Address 0x17d0b710 is 0 bytes inside a block of size 32 free'd
==27226== at 0x4C27D4E: free (vg_replace_malloc.c:427)
==27226== by 0xA138F42: PmmREFCNT_dec (in /usr/lib/perl5/auto/XML/LibXML/LibXML.so)
==27226== by 0xA11D3FA: XS_XML__LibXML__Node_DESTROY (in /usr/lib/perl5/auto/XML/LibXML/LibXML.so)
==27226== by 0x4EE770B: Perl_pp_entersub (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4E7AB90: Perl_call_sv (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4EEDBD8: Perl_sv_clear (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4EEE291: Perl_sv_free2 (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4ED7BC2: Perl_hv_free_ent (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4EDA919: Perl_hv_common (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4F0EEC7: Perl_pp_delete (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4EDECE5: Perl_runops_standard (in /usr/lib/libperl.so.5.14.2)
==27226== by 0x4E80814: perl_run (in /usr/lib/libperl.so.5.14.2)
最佳答案
引用ikegami的评论,因为我无法更好地表达它:
如valgrind
的输出所示,在此特定实例中,问题出在XML::LibXML
中。
我认为,一旦理解并解决问题,就可以按照Sinan Ünür的建议更新XML::LibXML
了。不幸的是,从2.0001(Debian稳定版)更新到2.0116(CPAN版)并没有解决。
最终,解决该问题的方法是修改SetOfThings::explode
,以便它创建一个新实例并复制所需的属性,而不是克隆当前实例并删除该属性,不需要:
sub explode {
my $self = shift;
my $new = __PACKAGE__->new;
$new->some_attribute('whatever');
$new->set_of_things( map { $_->explode } $self->constraints );
return $new;
}
克隆然后删除的
SetOfThings
对象的属性之一是DOM,显然XML::LibXML
不满意。多亏了这些知识和发表的评论,我终于能够用很小的脚本重现我的问题,并发布了bug report:#!/usr/bin/perl
use strict;
use warnings;
use Clone 'clone';
use XML::LibXML;
my $dom1 = new XML::LibXML::Document;
my $dom2 = clone $dom1;
正如ikegami指出的那样,克隆Perl变量不会复制该库使用的underlying C structure。但是
XML::LibXML
确实提供了cloneNode
方法,因此将最后一行更改为my $dom2 = $dom1->cloneNode(1)
给出期望的结果。
关于perl - "PmmREFCNT_dec: REFCNT decremented below 0"是什么意思?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23569633/