2011-07-24 32 views
2

在一個小測試文件,我可以運行文件句柄和XML ::簡單 - >內存損壞。不能隔離問題

#!/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,所以該代碼是不是祕密,但我不知道去哪裏找的麻煩,我可以不包括在這個帖子實際原因的所有代碼。這涉及到水銀後端)。


由於根據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",也會崩潰(使用open)和其他作品。
  2. 我應該使用另一種方法從外部命令接收輸出嗎?是否期望XMLin()ta與open一起工作(但爲什麼它在一種情況下工作,然後呢?)?

或者他們是否簡單的提出了「錯誤」的問題(即無關緊要)?


UPDATE:一個多星期過去了,活動不亂舞在這裏,我解決它有點不同,現在,沒有任何問題。我將cjm的答案標記爲正確,因爲它讓我進一步瞭解錯誤分析。謝謝!

+0

爲什麼「使用open」? XML不是utf-8編碼; XML是二進制的,它由解析器來檢測編碼 - 這就是<?xml'的用途。 (這給瞭解析器足夠的關於編碼的信息來讀取charset =聲明,然後用它來實際解析文檔。)當然,這不應該導致段錯誤,但可能會有不良的交互。刪除'使用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解析器告訴我們。


更新:因爲它看起來像你使用 XML::Parser(通過其SAX接口 XML::SAX::Expat,我建議嘗試 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]'中出現了段錯誤,這看起來相當直觀:) – jrockway

+0

@jrockway, XML :: Simple本身是純Perl的,但它使用的低級XML解析器通常不是。但XML :: Simple可以直接使用XML :: Parser,或默認選擇任何解析器XML :: SAX。 – cjm

+0

我希望我可以給自己一個「好答案」徽章。 ;)它正確地指出問題不是來自任何Perl代碼(包括XML :: Simple的代碼),展示瞭如何識別哪個XML分析器可能被指責,並解釋瞭如何將XML :: Simple依靠外部XML解析庫。它確定了哪個解析器應該受到指責,並描述瞭如何強制使用替代解析器和可能更高質量的解析器。不錯的工作。 – DavidO