Commit efb8ad276d6 for php
commit efb8ad276d6fbd1d8b667607cf71248f55a0d5d1
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Sat Sep 26 18:15:03 2026 -0400
ext/libxml: Keep SimpleXML children alive across reconstruction
Reconstructing a SimpleXMLElement decremented the shared node and then
installed a new document while the old pointer was still set, so the
second decrement freed a node a child object still held. Clear the
pointer before the new node is installed.
Closes GH-23931
diff --git a/NEWS b/NEWS
index a4b3101252e..e5441fe6bc2 100644
--- a/NEWS
+++ b/NEWS
@@ -137,6 +137,10 @@ PHP NEWS
. Fixed exceptions from user-defined create_sid() handlers being replaced
by return-value validation errors. (Ilia Alshanetsky)
+- SimpleXML:
+ . Fixed reconstructing a SimpleXMLElement freeing a child element that
+ another variable still references. (Ilia Alshanetsky)
+
- Sockets:
. Fixed socket_select() silently truncating sets larger than FD_SETSIZE on
Windows. (David Carlier)
diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c
index c73bcf930cf..5fdc44c4115 100644
--- a/ext/libxml/libxml.c
+++ b/ext/libxml/libxml.c
@@ -1501,6 +1501,7 @@ PHP_LIBXML_API void php_libxml_node_decrement_resource(php_libxml_node_object *o
obj_node->_private = NULL;
}
}
+ object->node = NULL;
}
if (object != NULL && object->document != NULL) {
/* Safe to call as if the resource were freed then doc pointer is NULL */
diff --git a/ext/simplexml/tests/reconstruct_with_retained_child.phpt b/ext/simplexml/tests/reconstruct_with_retained_child.phpt
new file mode 100644
index 00000000000..c6a1cb41808
--- /dev/null
+++ b/ext/simplexml/tests/reconstruct_with_retained_child.phpt
@@ -0,0 +1,19 @@
+--TEST--
+SimpleXMLElement reconstruction with a retained child
+--EXTENSIONS--
+simplexml
+--FILE--
+<?php
+$xml = simplexml_load_string('<root><child>old</child></root>');
+$child = $xml->child;
+
+$xml->__construct('<root><new>new</new></root>');
+
+var_dump((string) $xml->new);
+var_dump((string) $child);
+var_dump($child->asXML());
+?>
+--EXPECT--
+string(3) "new"
+string(3) "old"
+string(18) "<child>old</child>"