From c77a1291d612f5df913d8767938cd53ea75672d2 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 3 Oct 2024 07:56:12 +0200 Subject: [PATCH] Don't use recursion when transferring a DOM internal document pointer (#16180) Recursion is typically slower than iteration, and furthermore, this can cause problems in theory with deep trees. --- ext/dom/document.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/ext/dom/document.c b/ext/dom/document.c index 9650d090290..804efe727ff 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -1074,7 +1074,7 @@ PHP_METHOD(DOMDocument, getElementById) } /* }}} end dom_document_get_element_by_id */ -static zend_always_inline void php_dom_transfer_document_ref_single_node(xmlNodePtr node, php_libxml_ref_obj *new_document) +static void php_dom_transfer_document_ref_single_node(xmlNodePtr node, php_libxml_ref_obj *new_document) { php_libxml_node_ptr *iteration_object_ptr = node->_private; if (iteration_object_ptr) { @@ -1087,21 +1087,25 @@ static zend_always_inline void php_dom_transfer_document_ref_single_node(xmlNode } } +static void php_dom_transfer_document_ref_single_aux(xmlNodePtr node, php_libxml_ref_obj *new_document) +{ + php_dom_transfer_document_ref_single_node(node, new_document); + if (node->type == XML_ELEMENT_NODE) { + for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) { + php_dom_transfer_document_ref_single_node((xmlNodePtr) attr, new_document); + } + } +} + static void php_dom_transfer_document_ref(xmlNodePtr node, php_libxml_ref_obj *new_document) { - if (node->children) { - php_dom_transfer_document_ref(node->children, new_document); - } + xmlNodePtr base = node; + php_dom_transfer_document_ref_single_aux(base, new_document); - while (node) { - if (node->type == XML_ELEMENT_NODE) { - for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) { - php_dom_transfer_document_ref_single_node((xmlNodePtr) attr, new_document); - } - } - - php_dom_transfer_document_ref_single_node(node, new_document); - node = node->next; + node = node->children; + while (node != NULL) { + php_dom_transfer_document_ref_single_aux(node, new_document); + node = php_dom_next_in_tree_order(node, base); } }