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

Dan*_*son 2 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
}
Run Code Online (Sandbox Code Playgroud)

它工作正常.当我在一个更大的程序中运行相同的代码(使用相同的XML输入)时,它终止于

*** glibc detected *** /usr/bin/perl: malloc(): memory corruption: 0x0a40e308 ***
Run Code Online (Sandbox Code Playgroud)

(完全崩溃日志@ pastebin.com)

但是,如果我做交换

#open my $xml, "@cmdline |";
my $xml = `@cmdline`;
Run Code Online (Sandbox Code Playgroud)

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

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

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
Run Code Online (Sandbox Code Playgroud)

在大型项目中,和

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
Run Code Online (Sandbox Code Playgroud)

在测试文件中.


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

*** stack smashing detected ***: /usr/bin/perl terminated
Run Code Online (Sandbox Code Playgroud)

完全回溯@ 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()ta工作是否错误open(但为什么它在一个案例中起作用呢?)?

或者他们简单地提出要求的"错误"问题(即无关紧要)?


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

cjm*_*cjm 5

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

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

print "$_\n" for sort grep /XML/, keys %INC;
Run Code Online (Sandbox Code Playgroud)

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


更新:因为看起来你正在使用XML :: Parser(通过它的SAX接口XML :: SAX :: Expat,我建议尝试使用XML :: LibXML :: SAX .Libxml2被认为是更好的XML解析器之一.

如果您还没有安装XML :: LibXML :: SAX,只需安装它就应该将默认的SAX解析器切换到它.如果已安装,请尝试放置

$XML::SAX::ParserPackage = "XML::LibXML::SAX";
Run Code Online (Sandbox Code Playgroud)

在你的程序的开头.(有关如何选择SAX解析器,请参阅XML :: SAX :: ParserFactory.)