Commits

Shlomi Fish committed fb3f7fa

Fix RT #83779.

Comments (0)

Files changed (4)

         - "replaceNode() segfaults when copying DTD nodes with ATTLISTs"
         - Thanks to GUIDO@cpan.org for the report and to YOREEK for
         the patch.
+    - Apply fix for https://rt.cpan.org/Ticket/Display.html?id=83779
+        - "building on RHEL-5-64 fails"
+        - Thanks to mathias@koerber.org for the report, SREZIC@cpan.org
+        and d.thomas@its.uq.edu.au for taking part and Yuriy for the patch.
 
 2.0101          Thu 15 Aug 08:29:15 IDT 2013
     - Fixed https://rt.cpan.org/Ticket/Display.html?id=87089 .
 	  REPORT_ERROR(0);
           XSRETURN_UNDEF;
 	}
-        perl_doc = PmmNodeToSv((xmlNodePtr)doc, NULL);
-        if ( PmmREFCNT(SvPROXYNODE(perl_doc))==1 ) {
-	  /* will be decremented in Reader destructor */
-	  PmmREFCNT_inc(SvPROXYNODE(perl_doc));
-	}
         if (xmlTextReaderGetParserProp(reader,XML_PARSER_VALIDATE))
             PmmInvalidatePSVI(doc); /* the document may have psvi info */
 
     PREINIT:
         xmlNodePtr node;
         xmlDocPtr doc;
-        SV * perl_doc;
+        ProxyNodePtr proxy;
 	PREINIT_SAVED_ERROR
     CODE:
 	INIT_ERROR_HANDLER;
 	  REPORT_ERROR(0);
 	  XSRETURN_UNDEF;
 	}
-        perl_doc = PmmNodeToSv((xmlNodePtr)doc, NULL);
-        if ( PmmREFCNT(SvPROXYNODE(perl_doc))==1 ) {
-	  /* will be decremented in Reader destructor */
-	  PmmREFCNT_inc(SvPROXYNODE(perl_doc));
+    proxy = PmmNewNode((xmlNodePtr)doc);
+    if ( PmmREFCNT(proxy) == 0 ) {
+	  /* new proxy node */
+	  PmmREFCNT_inc(proxy);
 	}
 	node = xmlTextReaderPreserve(reader);
         CLEANUP_ERROR_HANDLER;
 	REPORT_ERROR(0);
         if (node) {
-           RETVAL = PmmNodeToSv(node, PmmOWNERPO(PmmPROXYNODE(doc)));
+           RETVAL = PmmNodeToSv(node, proxy);
 	} else {
 	    XSRETURN_UNDEF;
 	}
 	xmlTextReaderPtr reader
     PREINIT:
         xmlDocPtr doc;
-        SV * perl_doc;
+        ProxyNodePtr proxy;
 	/* SV * error_sv = NULL;
            xmlTextReaderErrorFunc f = NULL; */
     CODE:
 
-    if (xmlTextReaderReadState(reader) != XML_TEXTREADER_MODE_EOF) {
-        doc = xmlTextReaderCurrentDoc(reader);
-        if (doc) {
-            perl_doc = PmmNodeToSv((xmlNodePtr)doc, NULL);
-            if ( PmmREFCNT(SvPROXYNODE(perl_doc))>1 ) {
-                /* was incremented in document() to prevent from PMM destruction */
-                PmmREFCNT_dec(SvPROXYNODE(perl_doc));
-            }
-            SvREFCNT_dec(perl_doc);
+    doc = xmlTextReaderCurrentDoc(reader);
+    if (doc) {
+        proxy = PmmNewNode((xmlNodePtr)doc);
+        if ( PmmREFCNT(proxy) > 0 ) {
+            PmmREFCNT_dec(proxy);
         }
     }
         if (xmlTextReaderReadState(reader) != XML_TEXTREADER_MODE_CLOSED) {
 t/48_memleak_rt_83744.t
 t/48_removeChild_crashes_rt_80395.t
 t/48_replaceNode_DTD_nodes_rT_80521.t
+t/48_RH5_double_free_rt83779.t
 t/49_load_html.t
 t/49callbacks_returning_undef.t
 t/49global_extent.t

t/48_RH5_double_free_rt83779.t

+
+use strict;
+use warnings;
+use Scalar::Util qw(blessed);
+
+=head1 DESCRIPTION
+
+Double free on RHEL-5-x86_64.
+
+See L<https://rt.cpan.org/Ticket/Display.html?id=83779>.
+
+=cut
+
+use constant HAS_LEAKTRACE => eval{ require Test::LeakTrace };
+use Test::More HAS_LEAKTRACE ? (tests => 6) : (skip_all => 'Test::LeakTrace is required.');
+use Test::LeakTrace;
+use XML::LibXML::Reader;
+
+my $xml = <<'EOF';
+<html>
+  <head>
+    <title>David vs. Goliath - Part I</title>
+  </head>
+  <body>
+  </body>
+</html>
+EOF
+
+my $xml_decl = <<'EOF';
+<?xml version="1.0"?>
+EOF
+
+{
+    my $r = XML::LibXML::Reader->new(string => $xml);
+    my @nodes;
+    while ($r->read) {
+        push @nodes, $r->name;
+    }
+    # TEST
+    is(
+        join(',', @nodes),
+        'html,#text,head,#text,title,#text,title,#text,head,#text,body,#text,body,#text,html',
+        'Check reader'
+    );
+}
+
+{
+    my $r = XML::LibXML::Reader->new(string => $xml);
+    while ($r->read) {
+        $r->preserveNode();
+    }
+    # TEST
+    is(
+        $r->document->toString(),
+        $xml_decl . $xml,
+        'Check reader with using preserveNode'
+    );
+}
+
+{
+    my $r = XML::LibXML::Reader->new(string => $xml);
+    my $copy;
+    while ($r->read) {
+        $copy = $r->copyCurrentNode() if $r->name eq 'body';
+    }
+    # TEST
+    is(
+        $copy->toString(),
+        '<body/>',
+        'Check reader with using copyCurrentNode'
+    );
+}
+
+# TEST
+no_leaks_ok {
+    my $r = XML::LibXML::Reader->new(string => $xml);
+    while ($r->read) {
+        # nothing
+    }
+} 'Check reader, without leaks';
+
+# TEST
+no_leaks_ok {
+    my $node;
+    {
+        my $r = XML::LibXML::Reader->new(string => $xml);
+        while ($r->read) {
+            $node ||= $r->preserveNode();
+        }
+        my $doc = $r->document();
+    }
+} 'Check reader with using preserveNode, without leaks';
+
+# TEST
+no_leaks_ok {
+    my $r = XML::LibXML::Reader->new(string => $xml);
+    while ($r->read) {
+        my $copy = $r->copyCurrentNode();
+    }
+} 'Check reader with using copyCurrentNode, without leaks';