Filehandles和XML :: Simple - >内存损坏。无法隔离问题

时间:2011-07-24 23:33:13

标签: perl ikiwiki

在一个小测试文件中,我可以运行

#!/usr/bin/perl
use warnings;
use strict;
use open qw{:utf8 :std};
use XML::Simple;

my @cmdline = ("hg", "log", "-v", "--style", "xml");
open my $xml, "@cmdline |";

my $xmllog = XMLin($xml, ForceArray => ['logentry', 'parent', 'copy', 'path']);

foreach my $rev (@{$xmllog->{logentry}}) {
    #do stuff
}

它工作正常。当我在较大的程序中运行相同的代码(使用相同的XML输入)时,它以

结束
*** glibc detected *** /usr/bin/perl: malloc(): memory corruption: 0x0a40e308 ***

full crash log @ pastebin.com

但是,如果我进行交换

#open my $xml, "@cmdline |";
my $xml = `@cmdline`;

然后它起作用(在两个文件中),所以这更像是一个好奇的问题,而不是一个真正的问题。

  1. 有没有人对我的测试用例和更大的代码库之间的差异有什么指示?
  2. 有速度/记忆/?不同命令调用的区别?最佳做法?
  3. Debian Sid:Perl 5.12.4-1。

    (这是我第一次遇到Perl,所以不要过多地考虑我应该“了解”语言的内容。我只是潜入现有代码。)

    (较大的程序是ikiwiki,所以代码不是秘密,但我不知道在哪里寻找麻烦,并且出于实际原因我不能在这篇文章中包含所有代码。这涉及Mercurial后端。)


    根据cjm的建议,我添加了print "$_\n" for sort grep /XML/, keys %INC;,它提供了输出

    RPC/XML.pm
    RPC/XML/Client.pm
    RPC/XML/ParserFactory.pm
    XML/NamespaceSupport.pm
    XML/Parser.pm
    XML/Parser/Expat.pm
    XML/SAX.pm
    XML/SAX/Base.pm
    XML/SAX/Exception.pm
    XML/SAX/Expat.pm
    XML/SAX/ParserFactory.pm
    XML/Simple.pm
    

    在大项目中,

    XML/NamespaceSupport.pm
    XML/Parser.pm
    XML/Parser/Expat.pm
    XML/SAX.pm
    XML/SAX/Base.pm
    XML/SAX/Exception.pm
    XML/SAX/Expat.pm
    XML/SAX/ParserFactory.pm
    XML/Simple.pm
    

    在测试文件中。


    更新:我安装了Debian软件包libxml-libxml-perl并按照建议添加了$XML::SAX::ParserPackage = "XML::LibXML::SAX";。这也崩溃了,这次有不同的消息:

    *** stack smashing detected ***: /usr/bin/perl terminated
    

    full backtrace @ pastebin.com

    但这次在大文件和小文件中都是一致的。此外,仅在使用open时,而不是在使用反引号时。

    我还安装了libxml-libxml-simple-perl,但实际上这不应该是一个总是使用XML :: LibXML作为解析器的包装器。它的表现也不同,并抱怨设置的XMLin()的选项,所以我放弃了它。

    尝试明确(并盲目地)使程序使用print "$_\n" for sort grep /XML/, keys %INC;给出的每个替代方案似乎都指向XML :: SAX :: Expat默认使用cjm表示(因为所有其他选择退出有错误,XML :: SAX:Expat的行为与两个文件中的原始问题完全一样。明确要求XML :: Simple进入一个循环,分配我所有的内存。)

    我很感谢学习不同的XML解析器,并且XML :: Simple会自动选择不同的XML解析器。我原来问题的两个部分都有些保留:

    1. 为什么程序的行为不同?即使我在两个程序中明确设置$XML::SAX::ParserPackage = "XML::SAX::Expat",一个崩溃(使用open),另一个工作。
    2. 我应该使用其他方法接收外部命令的输出吗?期望XMLin()与open一起工作甚至是错误的(但为什么它在一个案例中起作用呢?)?
    3. 或者他们简单地提出要求的“错误”问题(即不相关)?


      更新:超过一个星期过去了,而不是一连串的活动,我现在解决它有点不同,没有问题。我将cjm的答案标记为正确,因为它让我在错误分析中得到了进一步的帮助。谢谢!

1 个答案:

答案 0 :(得分:5)

XML::Simple是纯Perl,因此不太可能导致您报告的内存损坏。它取决于较低级别的XML解析器,而且您遇到的错误可能就在那里。但是它可以使用多个解析器,我们需要知道哪一个。

尝试在示例程序的XMLin行后面添加此行,并使用结果更新您的问题:

print "$_\n" for sort grep /XML/, keys %INC;

这将告诉我们您在系统上实际使用的XML解析器。

<小时/> 更新:由于看起来您正在使用XML::Parser(通过其SAX界面XML::SAX::Expat,我建议您尝试使用XML::LibXML::SAX .Libxml2被认为是更好的XML解析器。

如果您还没有安装XML :: LibXML :: SAX,只需安装它就可以将默认的SAX解析器切换到它。如果已安装,请尝试添加

$XML::SAX::ParserPackage = "XML::LibXML::SAX";

在您的计划开始时。 (有关如何选择SAX解析器,请参阅XML::SAX::ParserFactory。)