【问题标题】:perl libXML crash when validating against XSD验证 XSD 时 perl libXML 崩溃
【发布时间】:2014-03-03 02:16:10
【问题描述】:

我正在将应用程序迁移到最新的 Debian,并且在针对 XSD 验证 XML 时遇到一个奇怪的服务器错误

use strict;
use feature qw( :5.10.0 );

use XML::LibXML;

my $xsd = q{
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="shiporder">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="orderperson" type="xs:string"/>
        <xs:element name="shipto">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="name" type="xs:string"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
      <xs:attribute name="orderid" type="xs:string" use="required"/>
    </xs:complexType>
  </xs:element>
</xs:schema>
};

my $soap=q{
<soap:Envelope
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <shiporder
        orderid="889923"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="shiporder.xsd">
      <orderperson>John Smith</orderperson>
      <shipto>
        <name>Ola Nordmann</name>
      </shipto>
    </shiporder>
  </soap:Body>
</soap:Envelope>
};

my $xmlparser = XML::LibXML->new();
my $doc = $xmlparser->parse_string($soap);
my $nodelist = $doc->getElementsByTagNameNS('http://schemas.xmlsoap.org/soap/envelope/', 'Body');

say $nodelist->[0]->toString();

XML::LibXML::Schema->new(string => $xsd)->validate($nodelist->[0]);

导致

* 检测到 glibc perl: free(): invalid pointer: 0x0000000001cca220 ** ======= 回溯:========= /lib/x86_64-linux-gnu/libc.so.6(+0x76d76)[0x7fa0edd5fd76] /usr/lib/perl5/auto/XML/LibXML/LibXML.so(PmmREFCNT_dec+0xa3)[0x7fa0ed27c543] /usr/lib/perl5/auto/XML/LibXML/LibXML.so(XS_XML_LibXML_Node_DESTROY+0xeb)[0x7fa0ed260a4b] /usr/lib/libperl.so.5.14(Perl_pp_entersub+0x58c)[0x7fa0ee7ce70c] /usr/lib/libperl.so.5.14(Perl_runops_standard+0x16)[0x7fa0ee7c5ce6] /usr/lib/libperl.so.5.14(Perl_call_sv+0x45b)[0x7fa0ee7619db] /usr/lib/libperl.so.5.14(Perl_sv_clear+0x559)[0x7fa0ee7d4bd9] /usr/lib/libperl.so.5.14(Perl_sv_free2+0x52)[0x7fa0ee7d5292] /usr/lib/libperl.so.5.14(Perl_leave_scope+0x122f)[0x7fa0ee7fccef] /usr/lib/libperl.so.5.14(Perl_pp_leave+0xf2)[0x7fa0ee7cb112] /usr/lib/libperl.so.5.14(Perl_runops_standard+0x16)[0x7fa0ee7c5ce6] /usr/lib/libperl.so.5.14(perl_run+0x3a5)[0x7fa0ee767815] perl(main+0x149)[0x400f89] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd)[0x7fa0edd07ead] perl [0x400fc1] ======= 内存映射:======== 00400000-00402000 r-xp 00000000 08:01 137813 /usr/bin/perl

等等

我认为在尝试释放分配的内存时它失败了。我试过克隆这些对象,但似乎没有什么能阻止它。这在全新安装 wheezy 和 jessie 时失败

【问题讨论】:

标签: linux perl debian libxml2 xml-libxml


【解决方案1】:

正如@nwellnhof 在单独的答案中所说, validate 期望将文档作为参数,而不是节点

所以我从节点创建了一个新文档,然后验证

my $xmlparser = XML::LibXML->new();
my $doc = $xmlparser->parse_string($soap);
my ($node) = $doc->findnodes('/soap:Envelope/soap:Body/*');

my $newDoc = XML::LibXML::Document->new("1.0");

$newDoc->setDocumentElement($node->cloneNode(1));
say $newDoc;

XML::LibXML::Schema->new(string => $xsd)->validate($newDoc);

【讨论】:

  • 如果你需要添加命名空间属性这是my $newDoc = XML::LibXML::Document-&gt;new("1.0"); my $newNode = $nodelist[0]-&gt;getChildrenByTagName('*')-&gt;shift()-&gt;cloneNode(1); $newNode-&gt;setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema"); $newDoc-&gt;setDocumentElement($newNode);的方法
【解决方案2】:

XML::LibXML::Schema 中的 validate 方法仅适用于整个文档。 libxml2 也提供了xmlSchemaValidateOneElement,但在 XML::LibXML 中没有此函数的绑定。

编辑: 这已在 XML::LibXML 2.0112 中修复。现在你可以pass nodes to validate

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-23
    • 1970-01-01
    • 2013-09-25
    • 2018-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多