diff --git a/NEWS b/NEWS index ba832ef05888..ececa76d4eb2 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,10 @@ PHP NEWS . Fixed bug GH-22447 (UAF at dom_objects_free_storage when setting an attribute node that collides by local name with a namespaced attribute). (David Carlier) + . Fixed bug GH-23116 (Stack overflow when normalizing a deeply nested + DOMDocument). (Weilin Du) + . Fixed bug GH-23117 (Stack overflow when normalizing a deeply nested + Dom\XMLDocument). (Weilin Du) - MBString: . Fixed bug GH-22779 (mb_strrpos() returns the wrong position for a negative diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 135b3cdc5caa..2cf97014896b 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -1975,25 +1975,25 @@ void php_dom_normalize_legacy(xmlNodePtr nodep) case XML_TEXT_NODE: dom_merge_adjacent_exclusive_text_nodes(child); if (is_empty_node(child)) { - xmlNodePtr nextp = child->next; + xmlNodePtr nextp = php_dom_next_in_tree_order(child, nodep); xmlUnlinkNode(child); free_node(child); child = nextp; continue; } break; - case XML_ELEMENT_NODE: - php_dom_normalize_legacy(child); + case XML_ELEMENT_NODE: { xmlAttrPtr attr = child->properties; while (attr != NULL) { php_dom_normalize_legacy((xmlNodePtr) attr); attr = attr->next; } break; + } default: break; } - child = child->next; + child = php_dom_next_in_tree_order(child, nodep); } } /* }}} end php_dom_normalize_legacy */ @@ -2011,7 +2011,7 @@ void php_dom_normalize_modern(xmlNodePtr this) /* 2. If length is zero, then remove node and continue with the next exclusive Text node, if any. */ if (is_empty) { - xmlNodePtr next = node->next; + xmlNodePtr next = php_dom_next_in_tree_order(node, this); xmlUnlinkNode(node); free_node(node); node = next; @@ -2025,10 +2025,8 @@ void php_dom_normalize_modern(xmlNodePtr this) dom_merge_adjacent_exclusive_text_nodes(node); /* Steps 5-6 deal with mutation records, we don't do that here. */ - } else if (node->type == XML_ELEMENT_NODE) { - php_dom_normalize_modern(node); } - node = node->next; + node = php_dom_next_in_tree_order(node, this); } } diff --git a/ext/dom/tests/gh23116.phpt b/ext/dom/tests/gh23116.phpt new file mode 100644 index 000000000000..80290d146881 --- /dev/null +++ b/ext/dom/tests/gh23116.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-23116 (Stack overflow when normalizing a deeply nested DOMDocument) +--EXTENSIONS-- +dom +--FILE-- +createElement('leaf'); +$node->appendChild($doc->createTextNode('x')); +$node->appendChild($doc->createTextNode('')); +$node->appendChild($doc->createTextNode('y')); +$leaf = $node; + +for ($i = 0; $i < 100000; $i++) { + $parent = $doc->createElement('a'); + $parent->appendChild($node); + $node = $parent; +} + +$doc->appendChild($node); +$doc->normalize(); + +var_dump($leaf->childNodes->length); +var_dump($leaf->textContent); +?> +--EXPECT-- +int(1) +string(2) "xy" diff --git a/ext/dom/tests/modern/xml/gh23117.phpt b/ext/dom/tests/modern/xml/gh23117.phpt new file mode 100644 index 000000000000..f70097843df4 --- /dev/null +++ b/ext/dom/tests/modern/xml/gh23117.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-23117 (Stack overflow when normalizing a deeply nested Dom\XMLDocument) +--EXTENSIONS-- +dom +--FILE-- +createElement('leaf'); +$node->appendChild($doc->createTextNode('x')); +$node->appendChild($doc->createTextNode('')); +$node->appendChild($doc->createTextNode('y')); +$leaf = $node; + +for ($i = 0; $i < 100000; $i++) { + $parent = $doc->createElement('a'); + $parent->appendChild($node); + $node = $parent; +} + +$doc->appendChild($node); +$doc->normalize(); + +var_dump($leaf->childNodes->length); +var_dump($leaf->textContent); +?> +--EXPECT-- +int(1) +string(2) "xy"