2

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

#!/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 ***

完整的崩溃日志@pastebin.com

但是,如果我进行交换

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

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

  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

在大型项目中,以及

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

完整的回溯@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 会自动选择不同的解析器。我原来的问题的两个部分都有些保留:

  1. 为什么程序的行为不同?即使我$XML::SAX::ParserPackage = "XML::SAX::Expat"在两个程序中都明确设置,一个崩溃(使用open)而另一个工作。
  2. 我应该使用另一种方法来接收来自外部命令的输出吗?期望 XMLin() 可以使用它甚至是错误的open(但是为什么它在一种情况下可以工作呢?)?

或者它们是简单的“错误”问题(即不相关)?


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

4

1 回答 1

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 。)

于 2011-07-25T01:16:33.217 回答