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 シド: 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;、cjm が言ったように、XML::SAX::Expat がデフォルトで使用されることを示しているようです (他のすべての代替手段はエラーで終了し、XML::SAX のため) :Expat は、両方のファイルで元の問題とまったく同じように動作します. 明示的に要求する XML::Simple は、すべてのメモリを割り当てるループに入ります)。

さまざまな XML パーサーについて学び、XML::Simple がさまざまなパーサーを自動的に選択してくれることに感謝しています。ただし、元の質問の両方の部分が多少残っています。

  1. プログラムの動作が異なるのはなぜですか? 両方のプログラムで明示的に設定$XML::SAX::ParserPackage = "XML::SAX::Expat"しても、一方がクラッシュし (を使用open)、もう一方が動作します。
  2. 外部コマンドからの出力を受け取るために別の方法を使用する必要がありますか? XMLin() が動作することを期待するのは間違っていopenますか?

それとも、単純に「間違った」質問をしているだけですか (つまり、無関係ですか) ?


更新: 1 週間以上が経過しましたが、ここでは慌ただしい活動はありませんでした。問題なく解決しました。エラー分析をさらに進めることができたので、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 パーサーの 1 つと見なされます。 .

XML::LibXML::SAX をまだインストールしていない場合は、インストールするだけでデフォルトの SAX パーサーがそれに切り替わるはずです。インストールされている場合は、入れてみてください

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

プログラムの最初に。( SAX パーサーの選択方法については、XML::SAX::ParserFactoryを参照してください。)

于 2011-07-25T01:16:33.217 に答える