diff -Nura XML-LibXML-2.0101-orig/LibXML.xs XML-LibXML-2.0101/LibXML.xs
--- XML-LibXML-2.0101-orig/LibXML.xs 2013-08-15 08:26:18.000000000 +0300
+++ XML-LibXML-2.0101/LibXML.xs 2013-08-17 03:40:42.993527411 +0300
@@ -8790,11 +8790,6 @@
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 */
@@ -8873,7 +8868,7 @@
PREINIT:
xmlNodePtr node;
xmlDocPtr doc;
- SV * perl_doc;
+ ProxyNodePtr proxy;
PREINIT_SAVED_ERROR
CODE:
INIT_ERROR_HANDLER;
@@ -8883,16 +8878,16 @@
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;
}
@@ -8961,20 +8956,16 @@
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) {
diff -Nura XML-LibXML-2.0101-orig/t/48_RH5_double_free_rt83779.t XML-LibXML-2.0101/t/48_RH5_double_free_rt83779.t
--- XML-LibXML-2.0101-orig/t/48_RH5_double_free_rt83779.t 1970-01-01 03:00:00.000000000 +0300
+++ XML-LibXML-2.0101/t/48_RH5_double_free_rt83779.t 2013-08-17 05:03:50.367641211 +0300
@@ -0,0 +1,100 @@
+
+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';