[php-src] PHP-8.5: Merge branch 'PHP-8.4' into PHP-8.5

Ilia Alshanetsky <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Ilia Alshanetsky (iliaal)
Date: 2026-08-18T14:47:59-04:00

Commit: https://github.com/php/php-src/commit/45013aad38a7da60b81094544c616cc81434ff5d
Raw diff: https://github.com/php/php-src/commit/45013aad38a7da60b81094544c616cc81434ff5d.diff

Merge branch 'PHP-8.4' into PHP-8.5

* PHP-8.4:
  Fix UAF when setAttributeNS() frees a wrapped attribute child

Changed paths:
  A  ext/dom/tests/modern/common/Element_setAttributeNS_live_child.phpt
  M  NEWS
  M  ext/dom/element.c


Diff:

diff --git a/NEWS b/NEWS
index 0fba79b14e96..149cfc869e3f 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,8 @@ PHP                                                                        NEWS
     and a later callback returns a node from another document. (iliaal)
   . Fixed bug GH-23331 (UAF when node_list_unlink() skips attribute children
     that still have a live wrapper). (iliaal)
+  . Fixed a use-after-free when Dom\Element::setAttributeNS() replaces the
+    value of an attribute whose child still has a live wrapper. (iliaal)
 
 - Intl:
   . Fixed a double-free when IntlGregorianCalendar construction fails after
diff --git a/ext/dom/element.c b/ext/dom/element.c
index 493e8a35410f..2320216f8244 100644
--- a/ext/dom/element.c
+++ b/ext/dom/element.c
@@ -1059,6 +1059,10 @@ static void dom_set_attribute_ns_modern(dom_object *intern, xmlNodePtr elemp, ze
 	if (errorcode == 0) {
 		php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(intern);
 		xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns_raw_prefix_string(ns_mapper, prefix, xmlStrlen(prefix), uri);
+		xmlNodePtr existing = (xmlNodePtr) xmlHasNsProp(elemp, localname, ns == NULL ? NULL : ns->href);
+		if (existing != NULL && existing->type != XML_ATTRIBUTE_DECL) {
+			node_list_unlink(existing->children);
+		}
 		xmlAttrPtr attr = xmlSetNsProp(elemp, ns, localname, BAD_CAST value);
 		if (UNEXPECTED(attr == NULL)) {
 			php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
diff --git a/ext/dom/tests/modern/common/Element_setAttributeNS_live_child.phpt b/ext/dom/tests/modern/common/Element_setAttributeNS_live_child.phpt
new file mode 100644
index 000000000000..22475c33cf88
--- /dev/null
+++ b/ext/dom/tests/modern/common/Element_setAttributeNS_live_child.phpt
@@ -0,0 +1,37 @@
+--TEST--
+setAttributeNS() keeps an attribute child that still has a live wrapper
+--EXTENSIONS--
+dom
+--FILE--
+<?php
+
+$doc = Dom\XMLDocument::createFromString('<root xmlns:p="urn:x" p:attr="old"/>');
+$el = $doc->documentElement;
+$text = $el->getAttributeNodeNS('urn:x', 'attr')->firstChild;
+$el->setAttributeNS('urn:x', 'p:attr', 'new');
+echo "prefixed, detached: ";
+var_dump($text->parentNode === null);
+echo "prefixed, text: ";
+var_dump($text->textContent);
+echo "prefixed, new value: ";
+var_dump($el->getAttributeNS('urn:x', 'attr'));
+
+$doc = Dom\XMLDocument::createFromString('<root attr="old"/>');
+$el = $doc->documentElement;
+$text = $el->getAttributeNode('attr')->firstChild;
+$el->setAttributeNS(null, 'attr', 'new');
+echo "no namespace, detached: ";
+var_dump($text->parentNode === null);
+echo "no namespace, text: ";
+var_dump($text->textContent);
+echo "no namespace, new value: ";
+var_dump($el->getAttribute('attr'));
+
+?>
+--EXPECT--
+prefixed, detached: bool(true)
+prefixed, text: string(3) "old"
+prefixed, new value: string(3) "new"
+no namespace, detached: bool(true)
+no namespace, text: string(3) "old"
+no namespace, new value: string(3) "new"
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.