Commit 4ee275fd59f for php.net
commit 4ee275fd59fc9ec33361789e44a16dd030a7e819
Author: David Carlier <devnexen@gmail.com>
Date: Sat Mar 28 14:21:35 2026 +0000
Fix GH-21548: Dom\XMLDocument::C14N() emits duplicate xmlns declarations after setAttributeNS().
The xmlns attribute unlinking code in dom_relink_ns_decls_element was
clobbering attr->prev instead of updating the predecessor's next pointer,
leaving non-first xmlns attributes reachable in the properties list.
C14N then output them both as nsDef entries and as attributes.
close GH-21566
diff --git a/NEWS b/NEWS
index dc0e430775f..8ed1497997a 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,10 @@ PHP NEWS
. Fixed bug GH-19983 (GC assertion failure with fibers, generators and
destructors). (iliaal)
+- DOM:
+ . Fixed bug GH-21566 (Dom\XMLDocument::C14N() emits duplicate xmlns
+ declarations after setAttributeNS()). (David Carlier)
+
- SPL:
. Fixed bug GH-21499 (RecursiveArrayIterator getChildren UAF after parent
free). (Girgias)
diff --git a/ext/dom/node.c b/ext/dom/node.c
index 9c1a508d669..83404d0f598 100644
--- a/ext/dom/node.c
+++ b/ext/dom/node.c
@@ -2132,7 +2132,7 @@ static void dom_relink_ns_decls_element(HashTable *links, xmlNodePtr node)
ns->_private = attr;
if (attr->prev) {
- attr->prev = attr->next;
+ attr->prev->next = attr->next;
} else {
node->properties = attr->next;
}
diff --git a/ext/dom/tests/modern/xml/gh21548.phpt b/ext/dom/tests/modern/xml/gh21548.phpt
new file mode 100644
index 00000000000..55299c8d6e6
--- /dev/null
+++ b/ext/dom/tests/modern/xml/gh21548.phpt
@@ -0,0 +1,17 @@
+--TEST--
+GH-21548 (Dom\XMLDocument::C14N() emits duplicate xmlns declarations after setAttributeNS())
+--CREDITS--
+Toon Verwerft (veewee)
+--EXTENSIONS--
+dom
+--FILE--
+<?php
+
+$doc = Dom\XMLDocument::createFromString('<root xmlns="urn:a" attr="val"/>');
+$doc->documentElement->setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ns1", "urn:a");
+
+echo $doc->C14N() . PHP_EOL;
+
+?>
+--EXPECT--
+<root xmlns="urn:a" xmlns:ns1="urn:a" attr="val"></root>