From d027bc2addb4f12e0030532933a2c85c07cdb293 Mon Sep 17 00:00:00 2001 From: Tim Toohey Date: Sat, 3 Jun 2017 00:38:02 +0200 Subject: [PATCH] Fixed bug #69373 xmlNodeSetContentLen() calls xmlFreeNode() on node->children. This causes problems if there are other references around to those children. --- NEWS | 3 +++ ext/dom/node.c | 10 ++++++++++ ext/dom/tests/bug69373.phpt | 15 +++++++++++++++ ext/libxml/libxml.c | 2 +- ext/libxml/php_libxml.h | 1 + 5 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 ext/dom/tests/bug69373.phpt diff --git a/NEWS b/NEWS index eecf1e50a6..2cb059a5f1 100644 --- 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) diff --git a/ext/dom/node.c b/ext/dom/node.c index b4ab9f896a..b4a081ebe9 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -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 index 0000000000..d04ac03983 --- /dev/null +++ b/ext/dom/tests/bug69373.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #69373 References to deleted XPath query results +--FILE-- +loadXML(""); + $xpath = new DOMXpath($doc); + $all = $xpath->query('//*'); + $doc->firstChild->nodeValue = ''; +} +echo 'DONE', PHP_EOL; +?> +--EXPECT-- +DONE diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 12f1c2c3d0..a029b9f477 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -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; diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h index 88ab22928b..5021a3d43f 100644 --- a/ext/libxml/php_libxml.h +++ b/ext/libxml/php_libxml.h @@ -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); -- 2.40.0