From f33c5f222bc7266fa95a2223f7647d058efe42d7 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Thu, 24 Sep 2026 18:37:47 -0400 Subject: [PATCH] Fix SimpleXML reconstruction use-after-free Clear the consumed libxml node pointer when releasing an object resource so SimpleXML reconstruction does not retain a dangling wrapper. Retained child nodes keep their document reference and remain usable. --- ext/libxml/libxml.c | 1 + .../reconstruct_with_retained_child.phpt | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 ext/simplexml/tests/reconstruct_with_retained_child.phpt diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index c73bcf930cfd..5fdc44c4115f 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 000000000000..c6a1cb418089 --- /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-- +old'); +$child = $xml->child; + +$xml->__construct('new'); + +var_dump((string) $xml->new); +var_dump((string) $child); +var_dump($child->asXML()); +?> +--EXPECT-- +string(3) "new" +string(3) "old" +string(18) "old"