From 11ad086effdb093a416a54dafe42af785cf7f449 Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Thu, 13 Jul 2023 15:06:07 +0200
Subject: [PATCH 1/2] Add regression test with wrong output
---
...ragments_multiple_nodes_DOMParentNode.phpt | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 ext/dom/tests/fragments_multiple_nodes_DOMParentNode.phpt
diff --git a/ext/dom/tests/fragments_multiple_nodes_DOMParentNode.phpt b/ext/dom/tests/fragments_multiple_nodes_DOMParentNode.phpt
new file mode 100644
index 0000000000000..89d38221852fb
--- /dev/null
+++ b/ext/dom/tests/fragments_multiple_nodes_DOMParentNode.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Handling fragments of multiple nodes for DOMParentNode
+--EXTENSIONS--
+dom
+--FILE--
+loadXML('
1
+ + +1
foo + + +3
1
foo From 06603ad90dde29b634987e4b6b52a7f1c28ff5cb Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 13 Jul 2023 15:11:29 +0200 Subject: [PATCH 2/2] Handle fragments consisting out of multiple children without a single root correctly --- ext/dom/parentnode.c | 30 +++++++++---------- ...ragments_multiple_nodes_DOMParentNode.phpt | 6 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ext/dom/parentnode.c b/ext/dom/parentnode.c index dba580ead7cd7..8467fbf0603a4 100644 --- a/ext/dom/parentnode.c +++ b/ext/dom/parentnode.c @@ -183,15 +183,7 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod goto err; } - if (newNode->type == XML_DOCUMENT_FRAG_NODE) { - /* Unpack document fragment nodes, the behaviour differs for different libxml2 versions. */ - newNode = newNode->children; - if (UNEXPECTED(newNode == NULL)) { - /* No nodes to add, nothing to do here */ - continue; - } - xmlUnlinkNode(newNode); - } else if (newNode->parent != NULL) { + if (newNode->parent != NULL) { xmlUnlinkNode(newNode); } @@ -210,14 +202,23 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod newNode = xmlCopyNode(newNode, 1); } - if (!xmlAddChild(fragment, newNode)) { + if (newNode->type == XML_DOCUMENT_FRAG_NODE) { + /* Unpack document fragment nodes, the behaviour differs for different libxml2 versions. */ + newNode = newNode->children; + while (newNode) { + xmlNodePtr next = newNode->next; + xmlUnlinkNode(newNode); + if (!xmlAddChild(fragment, newNode)) { + goto hierarchy_request_err; + } + newNode = next; + } + } else if (!xmlAddChild(fragment, newNode)) { if (will_free) { xmlFreeNode(newNode); } goto hierarchy_request_err; } - - continue; } else { zend_argument_type_error(i + 1, "must be of type DOMNode|string, %s given", zend_zval_type_name(&nodes[i])); goto err; @@ -363,14 +364,13 @@ static void dom_pre_insert(xmlNodePtr insertion_point, xmlNodePtr parentNode, xm /* Place it as last node */ if (parentNode->children) { /* There are children */ - fragment->last->prev = parentNode->last; - newchild->prev = parentNode->last->prev; + newchild->prev = parentNode->last; parentNode->last->next = newchild; } else { /* No children, because they moved out when they became a fragment */ parentNode->children = newchild; - parentNode->last = newchild; } + parentNode->last = fragment->last; } else { /* Insert fragment before insertion_point */ fragment->last->next = insertion_point; diff --git a/ext/dom/tests/fragments_multiple_nodes_DOMParentNode.phpt b/ext/dom/tests/fragments_multiple_nodes_DOMParentNode.phpt index 89d38221852fb..3997a23ca972f 100644 --- a/ext/dom/tests/fragments_multiple_nodes_DOMParentNode.phpt +++ b/ext/dom/tests/fragments_multiple_nodes_DOMParentNode.phpt @@ -29,10 +29,10 @@ echo $dom->saveXML(); --EXPECT-- -1
+1
2 -1
foo +1
2foo -3
1
foo +3
41
2foo