From d9329b15220ecc127cfce75d4fe1b6ca6fc6236d Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 17 Mar 2025 20:05:43 +0100 Subject: [PATCH] Fix xinclude destruction of live attributes Follow-up for GH-17847 but now for attributes. Closes GH-18100. --- NEWS | 1 + ext/dom/document.c | 14 ++++++++++++++ ext/dom/tests/gh17847.phpt | 33 ++++++++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 59b66e85f84..46510db971e 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ PHP NEWS - DOM: . Fix weird unpack behaviour in DOM. (nielsdos) + . Fix xinclude destruction of live attributes. (nielsdos) - GD: . Fixed bug GH-17984 (calls with arguments as array with references). diff --git a/ext/dom/document.c b/ext/dom/document.c index 0388249766e..42d67d57398 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -1607,14 +1607,28 @@ static zend_always_inline xmlNodePtr php_dom_next_in_tree_order(const xmlNode *n } } +static void dom_xinclude_strip_references_for_attributes(xmlNodePtr basep) +{ + for (xmlAttrPtr prop = basep->properties; prop; prop = prop->next) { + php_libxml_node_free_resource((xmlNodePtr) prop); + for (xmlNodePtr child = prop->children; child; child = child->next) { + php_libxml_node_free_resource(child); + } + } +} + static void dom_xinclude_strip_references(xmlNodePtr basep) { php_libxml_node_free_resource(basep); + dom_xinclude_strip_references_for_attributes(basep); xmlNodePtr current = basep->children; while (current) { php_libxml_node_free_resource(current); + if (current->type == XML_ELEMENT_NODE) { + dom_xinclude_strip_references_for_attributes(current); + } current = php_dom_next_in_tree_order(current, basep); } } diff --git a/ext/dom/tests/gh17847.phpt b/ext/dom/tests/gh17847.phpt index 5d5df0b3be0..01601ca0352 100644 --- a/ext/dom/tests/gh17847.phpt +++ b/ext/dom/tests/gh17847.phpt @@ -13,7 +13,7 @@ $doc->loadXML(<< -

garbage

+

garbage

@@ -22,15 +22,22 @@ XML); $xpath = new DOMXPath($doc); $garbage = []; -foreach ($xpath->query('//p') as $entry) +foreach ($xpath->query('//p') as $entry) { $garbage[] = $entry; + foreach ($entry->attributes as $attr) { + $garbage[] = $attr; + foreach ($attr->childNodes as $child) { + $garbage[] = $child; + } + } +} @$doc->xinclude(); var_dump($garbage); ?> --EXPECT-- -array(3) { +array(7) { [0]=> object(DOMElement)#3 (1) { ["schemaTypeInfo"]=> @@ -46,4 +53,24 @@ array(3) { ["schemaTypeInfo"]=> NULL } + [3]=> + object(DOMAttr)#10 (2) { + ["specified"]=> + bool(true) + ["schemaTypeInfo"]=> + NULL + } + [4]=> + object(DOMText)#13 (0) { + } + [5]=> + object(DOMAttr)#12 (2) { + ["specified"]=> + bool(true) + ["schemaTypeInfo"]=> + NULL + } + [6]=> + object(DOMText)#15 (0) { + } }