Commit f9634847258 for php
commit f9634847258a8c3ed6c12bb79104eba60bb631ea
Author: evanford <evankerrickford@gmail.com>
Date: Wed Oct 21 14:15:22 2026 -0400
Fix GH-24488: GC double-frees the SimpleXMLElement properties table
Since the GH-24050 fix, gc_collect_white() adds the table returned by
get_gc to the garbage buffer. sxe_object_free_storage() released
sxe->properties with zend_hash_release(), which does not remove the
table from the GC buffer, so the GC later read and freed it again.
Use zend_array_release(), which goes through zend_array_destroy().
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Close GH-24494
diff --git a/NEWS b/NEWS
index 9336ed394c3..3d8db871d6c 100644
--- a/NEWS
+++ b/NEWS
@@ -107,6 +107,10 @@ PHP NEWS
. Fixed session data loss in the files save handler when writing the session
file fails after it was already truncated. (Ilia Alshanetsky)
+- SimpleXML:
+ . Fixed bug GH-24488 (GC double-frees the SimpleXMLElement properties
+ table). (evankford)
+
- Standard:
. Fixed bug GH-24399 (usleep() and time_nanosleep() ignore queued APCs on
Windows). (Nicolas Grekas)
diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c
index 7d4337ae384..b8475ec62c8 100644
--- a/ext/simplexml/simplexml.c
+++ b/ext/simplexml/simplexml.c
@@ -2202,7 +2202,7 @@ static void sxe_object_free_storage(zend_object *object)
if (sxe->properties) {
ZEND_ASSERT(!(GC_FLAGS(sxe->properties) & IS_ARRAY_IMMUTABLE));
- zend_hash_release(sxe->properties);
+ zend_array_release(sxe->properties);
}
}
/* }}} */
diff --git a/ext/simplexml/tests/gh24488.phpt b/ext/simplexml/tests/gh24488.phpt
new file mode 100644
index 00000000000..c8eaf25d489
--- /dev/null
+++ b/ext/simplexml/tests/gh24488.phpt
@@ -0,0 +1,24 @@
+--TEST--
+GH-24488 (GC double-frees the SimpleXMLElement properties table)
+--EXTENSIONS--
+simplexml
+--FILE--
+<?php
+
+for ($i = 0; $i < 2; $i++) {
+ $xml = new SimpleXMLElement('<a><b/></a>');
+ get_object_vars($xml);
+
+ $holder = new stdClass;
+ $holder->xml = $xml;
+ $holder->self = $holder;
+ unset($xml, $holder);
+
+ gc_collect_cycles();
+ $junk[] = str_repeat('x', 100);
+}
+
+echo "Done\n";
+?>
+--EXPECT--
+Done