From b0b621ed193015d917374c31174f94018fa41e5b Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 11 Oct 2024 21:46:30 +0200 Subject: [PATCH] Add missing hierarchy checks to replaceChild You can break the hierarchy for attribute nodes, use the helper function introduced recently [1] to fix this issue. [1] 066d18f2 --- ext/dom/node.c | 22 ++++----------- .../replaceChild_attribute_validation.phpt | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+), 17 deletions(-) create mode 100644 ext/dom/tests/replaceChild_attribute_validation.phpt diff --git a/ext/dom/node.c b/ext/dom/node.c index bb80408f2689..0972f14489a7 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -843,7 +843,7 @@ static xmlNodePtr _php_dom_insert_fragment(xmlNodePtr nodep, xmlNodePtr prevsib, } /* }}} */ -static bool dom_node_check_legacy_insertion_validity(xmlNodePtr parentp, xmlNodePtr child, bool stricterror) +static bool dom_node_check_legacy_insertion_validity(xmlNodePtr parentp, xmlNodePtr child, bool stricterror, bool warn_empty_fragment) { if (dom_node_is_read_only(parentp) == SUCCESS || (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) { @@ -861,7 +861,7 @@ static bool dom_node_check_legacy_insertion_validity(xmlNodePtr parentp, xmlNode return false; } - if (child->type == XML_DOCUMENT_FRAG_NODE && child->children == NULL) { + if (warn_empty_fragment && child->type == XML_DOCUMENT_FRAG_NODE && child->children == NULL) { /* TODO Drop Warning? */ php_error_docref(NULL, E_WARNING, "Document Fragment is empty"); return false; @@ -903,7 +903,7 @@ PHP_METHOD(DOMNode, insertBefore) stricterror = dom_get_strict_error(intern->document); - if (!dom_node_check_legacy_insertion_validity(parentp, child, stricterror)) { + if (!dom_node_check_legacy_insertion_validity(parentp, child, stricterror, true)) { RETURN_FALSE; } @@ -1066,19 +1066,7 @@ PHP_METHOD(DOMNode, replaceChild) stricterror = dom_get_strict_error(intern->document); - if (dom_node_is_read_only(nodep) == SUCCESS || - (newchild->parent != NULL && dom_node_is_read_only(newchild->parent) == SUCCESS)) { - php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror); - RETURN_FALSE; - } - - if (newchild->doc != nodep->doc && newchild->doc != NULL) { - php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror); - RETURN_FALSE; - } - - if (dom_hierarchy(nodep, newchild) == FAILURE) { - php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror); + if (!dom_node_check_legacy_insertion_validity(nodep, newchild, stricterror, false)) { RETURN_FALSE; } @@ -1185,7 +1173,7 @@ PHP_METHOD(DOMNode, appendChild) stricterror = dom_get_strict_error(intern->document); - if (!dom_node_check_legacy_insertion_validity(nodep, child, stricterror)) { + if (!dom_node_check_legacy_insertion_validity(nodep, child, stricterror, true)) { RETURN_FALSE; } diff --git a/ext/dom/tests/replaceChild_attribute_validation.phpt b/ext/dom/tests/replaceChild_attribute_validation.phpt new file mode 100644 index 000000000000..32d5990f75e3 --- /dev/null +++ b/ext/dom/tests/replaceChild_attribute_validation.phpt @@ -0,0 +1,27 @@ +--TEST-- +replaceChild with attribute children +--EXTENSIONS-- +dom +--FILE-- +createAttribute('attr'); +$attr->textContent = "test"; + +try { + $attr->replaceChild($dom->createProcessingInstruction('pi'), $attr->firstChild); +} catch (DOMException $e) { + echo $e->getMessage(), "\n"; +} + +$root = $dom->appendChild($dom->createElement('root')); +$root->setAttributeNode($attr); + +echo $dom->saveXML(); + +?> +--EXPECT-- +Hierarchy Request Error + +