2011-07-24 4 views
2

を特定することはできません、私はファイルハンドルとXML :: Simple-> Memory corruption。小さなテストファイルでは問題

#!/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. 速度/メモリ/はありますか?別のコマンド呼び出しの違いは?ベストプラクティス?

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は自動的に異なるものを選択します。私の元々の質問の両方の部分はやや残っています:

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

「または間違っている」質問は簡単ですか(無関係)?


UPDATE:一週間以上は、ここでは、活動のない突風を通過した、と私は問題もなく、今少し違っそれを解決します。私はcjmの答えを正しいとマークしています。なぜなら、それはエラー分析の中でさらに私を得ているからです。ありがとう!

+0

「オープン」を使用するのはなぜですか? XMLはutf-8でエンコードされていません。 XMLはバイナリで、エンコーディングを検出するのはパーサーに任されています。これが '<?xml'の目的です。 (これにより、パーサーは、文字セットを読むためのエンコーディングについての十分な情報を得ます。宣言は、実際にドキュメントを解析するために使用されます)。もちろん、セグメンテーションを引き起こすべきではありません。 'use open'を削除し、何が起こるかを見てください。 – jrockway

+0

また注目に値する:私はXML :: ParserのXSコードをすばやく見て、 "utf8フラグ"を使って非常に高速で遊ぶことに気づいた。バッファが有効かどうかにかかわらずフラグをオンにするutf8。 XML :: LibXMLを使用してください:) – jrockway

+0

"openを使用する"は、大きなプログラムで既に使用されていたヘッダーを再作成することだけでした。私は問題を分離するために環境を可能な限り等しくしたいと思っていましたが、そうではありませんでした。 –

答えて

5

XML::Simpleは純粋なPerlだから、あなたが報告したメモリ破損を引き起こす可能性は低いです。これは下位レベルのXMLパーサに依存しており、遭遇したバグが存在する可能性があります。しかし、使用できるパーサは複数あり、どちらを知る必要があります。

右あなたのサンプルプログラムでXMLin行の後にこの行を追加してみてください、との結果であなたの質問を更新します。

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

これはあなたが実際にあなたのシステム上で使用しているどのXMLパーサを教えてくれる。


更新:あなたはそのSAXインタフェースXML::SAX::Expatを通じて(XML::Parserを使用しているように見えるので、私の代わりに XML::LibXML::SAXを試みることをお勧めしたいLibxml2は、より良いXMLパーサの一つと考えられている

をそうしないと。すでにXML ::のlibxml :: SAXがインストールされ、それはそれにあなたのデフォルトのSAXパーサーを切り替える必要があります。それがインストールされている場合はインストールするには、あなたのプログラムの冒頭で

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

を入れて試してみる。(方法についてはXML::SAX::ParserFactoryを参照してください。 SAXパーサーが選択されています)

+0

XML :: SimpleはXML :: SAX :: Expatを呼び出すようですが、これは間違いなく純粋なperlではありません。ポストされたスタックトレースを見ると、 '/usr/lib/libexpat.so.1(XML_ParseBuffer + 0x7c)[0xb714464c]'にsegfaultsされていることがわかります。これはかなり外見です:) – jrockway

+0

@jrockway、 XML :: Simple自体は純粋なPerlですが、通常はそれが使用する下位レベルのXMLパーサーはありません。しかし、XML :: Simpleでは、XML :: Parserを直接使用することも、XML :: SAXがデフォルトで選択するパーサーを使用することもできます。 – cjm

+0

私は「Nice Answer」のバッジを自分に与えることができたらいいと思っています。 ;)これは、問題がPerlコード(XML :: Simpleのコードを含む)の中から来ていないことを正しく識別し、どのXMLパーサーが責任を負う可能性があるかを示し、XML :: Simple外部のXML解析ライブラリに依存しています。それは、どのパーサーが責任を負うべきかを特定し、代わりに、おそらくより高品質のパーサーを強制的に使用する方法を説明しました。良くやった。 – DavidO

関連する問題