perl - "PmmREFCNT_dec: REFCNT decremented below 0"是什么意思?

标签 perl segmentation-fault

我一定做了perl非常沮丧,因为它给了我一条错误消息,perldiag 中没有记录。 :

PmmREFCNT_dec: REFCNT decremented below 0 for 53a6930!.



根据其心情,有时会出现以下情况:

*** glibc detected *** /usr/bin/perl: double free or corruption (!prev): 0x0000000004e58a60 *



...或者更明确地说:

Segmentation fault



这显然是致命的,但我也测试过它是可捕获的。使用 Try::Tiny 时,我总是会在同一个地方捕获错误,但是当不使用它时,会在崩溃发生之前执行更多指令。此外,即使我的模块完全是确定性的,并且我很确定所有依赖项也是如此,但错误不会一直发生。

不幸的是,给我这个问题的模块很大,有很多依赖项,我无法在一个较小的例子中复制这个问题。因此,我无法寻求帮助来调试它,但是如果熟悉 Perl 内部的人知道在什么情况下会发生此错误,那可能会帮助我(或其他任何会看到此消息的人)找到问题的根源和/或一种解决方法。

如果它有用,一般的想法是这样的。我有两个类,我们叫他们ThingSetOfThings . 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的评论,因为我无法更好地表述它:

It's a bug in Perl or in an XS module. A variable should be freed when its reference count reaches zero, but something attempted to decrement a variable's reference count when it was already zero.



作为 valgrind 的输出表明,在这个特定的例子中,问题出在 XML::LibXML .

我认为更新 XML::LibXML ,正如 Sinan Ünür 所建议的那样只要问题被理解和解决就是要走的路。不幸的是,从 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/

相关文章:

Perl:为什么这会创建数千个子进程?

regex - 我可以从 perl 正则表达式中的单词字符集中消除下划线吗?

java - 这个正则表达式有什么作用?

c++ - 定义为 "_end[LEN]"的数组在 C/C++ 中导致段错误

c++ - 当我尝试调用 createTargetMachine() 时,为什么 LLVM 出现段错误?

c - 从 Perl 中的 IV* 中获取整数

database - 使用 Perl,如何使用 dbh csv_tables 从标准输入读取 CSV 字符串?

token 方法的 C 段故障 : Possible malloc error?

c++ - nvcc编译后出现段错误

python - 在 Python 中导入模块时出现段错误