Fixed bug #69373
authorTim Toohey <ttoohey@php.net>
Fri, 2 Jun 2017 22:38:02 +0000 (00:38 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 2 Jun 2017 22:40:58 +0000 (00:40 +0200)
xmlNodeSetContentLen() calls xmlFreeNode() on node->children. This
causes problems if there are other references around to those children.

NEWS
ext/dom/node.c
ext/dom/tests/bug69373.phpt [new file with mode: 0644]
ext/libxml/libxml.c
ext/libxml/php_libxml.h

diff --git a/NEWS b/NEWS
index eecf1e50a6b1b012b08c685265fc0b9aa28a5723..2cb059a5f1f92d751d4d035acc855b848393ea3b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,9 @@ PHP                                                                        NEWS
     properties). (Laruence)
   . Fixed misparsing of abstract unix domain socket names. (Sara)
 
+- DOM:
+  . Fixed bug #69373 (References to deleted XPath query results). (ttoohey)
+
 - Intl:
   . Fixed bug #73473 (Stack Buffer Overflow in msgfmt_parse_message). (libnex)
 
index b4ab9f896af57ba4e33d1718ce28f6d1c582b7d0..b4a081ebe9b1256c43d65370899b6f79820091f8 100644 (file)
@@ -337,6 +337,8 @@ int dom_node_node_value_write(dom_object *obj, zval *newval)
                case XML_ATTRIBUTE_NODE:
                        if (nodep->children) {
                                node_list_unlink(nodep->children);
+                               php_libxml_node_free_list((xmlNodePtr) nodep->children);
+                               nodep->children = NULL;
                        }
                case XML_TEXT_NODE:
                case XML_COMMENT_NODE:
@@ -854,6 +856,14 @@ int dom_node_text_content_write(dom_object *obj, zval *newval)
                return FAILURE;
        }
 
+       if (nodep->type == XML_ELEMENT_NODE || nodep->type == XML_ATTRIBUTE_NODE) {
+               if (nodep->children) {
+                       node_list_unlink(nodep->children);
+                       php_libxml_node_free_list((xmlNodePtr) nodep->children);
+                       nodep->children = NULL;
+               }
+       }
+
        str = zval_get_string(newval);
        /* we have to use xmlNodeAddContent() to get the same behavior as with xmlNewText() */
        xmlNodeSetContent(nodep, (xmlChar *) "");
diff --git a/ext/dom/tests/bug69373.phpt b/ext/dom/tests/bug69373.phpt
new file mode 100644 (file)
index 0000000..d04ac03
--- /dev/null
@@ -0,0 +1,15 @@
+--TEST--
+Bug #69373 References to deleted XPath query results
+--FILE--
+<?php
+$doc = new DOMDocument();
+for( $i=0; $i<20; $i++ ) {
+       $doc->loadXML("<parent><child /><child /></parent>");
+       $xpath = new DOMXpath($doc);
+       $all = $xpath->query('//*');
+       $doc->firstChild->nodeValue = '';
+}
+echo 'DONE', PHP_EOL;
+?>
+--EXPECT--
+DONE
index 12f1c2c3d04efe0f29f8d3a2177120a0cca5f660..a029b9f477a1799b5a34d4dfcc77dbe58927415f 100644 (file)
@@ -224,7 +224,7 @@ static void php_libxml_node_free(xmlNodePtr node)
        }
 }
 
-static void php_libxml_node_free_list(xmlNodePtr node)
+PHP_LIBXML_API void php_libxml_node_free_list(xmlNodePtr node)
 {
        xmlNodePtr curnode;
 
index 88ab22928bcb7cbcb8a871a71e4a53e6079b9725..5021a3d43f169b6a065df2125678ad2c85a720eb 100644 (file)
@@ -100,6 +100,7 @@ PHP_LIBXML_API int php_libxml_decrement_doc_ref(php_libxml_node_object *object);
 PHP_LIBXML_API xmlNodePtr php_libxml_import_node(zval *object);
 PHP_LIBXML_API zval *php_libxml_register_export(zend_class_entry *ce, php_libxml_export_node export_function);
 /* When an explicit freeing of node and children is required */
+PHP_LIBXML_API void php_libxml_node_free_list(xmlNodePtr node);
 PHP_LIBXML_API void php_libxml_node_free_resource(xmlNodePtr node);
 /* When object dtor is called as node may still be referenced */
 PHP_LIBXML_API void php_libxml_node_decrement_resource(php_libxml_node_object *object);