From 18b64b3062763ccad8e4a2d3ddb57528b3bb4eaf Mon Sep 17 00:00:00 2001 From: lazerg Date: Thu, 22 Oct 2026 18:37:35 +0500 Subject: [PATCH] Fix GH-24532: Reset unserialize var entries before running destructors --- NEWS | 2 ++ ext/standard/tests/serialize/gh24532.phpt | 33 +++++++++++++++++++++++ ext/standard/var_unserializer.re | 11 ++++++++ 3 files changed, 46 insertions(+) create mode 100644 ext/standard/tests/serialize/gh24532.phpt diff --git a/NEWS b/NEWS index 6bb8496271f8..92aa157571b2 100644 --- a/NEWS +++ b/NEWS @@ -167,6 +167,8 @@ PHP NEWS especially UTF-8. (Nicolas Grekas) . Improved performance of htmlspecialchars() when nothing needs encoding. (Nicolas Grekas) + . Fixed bug GH-24532 (unserialize() teardown should reset freed var entries + before running destructors). (lazerg) - URI: . Fix casing of enum cases in UriHostType and UrlHostType to match the RFC diff --git a/ext/standard/tests/serialize/gh24532.phpt b/ext/standard/tests/serialize/gh24532.phpt new file mode 100644 index 000000000000..c0fe24588082 --- /dev/null +++ b/ext/standard/tests/serialize/gh24532.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-24532 (unserialize() teardown should reset freed var entries before running destructors) +--FILE-- + +--EXPECT-- +int(1020) +int(1017) diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 89f1c5a1a88e..2652b5a0c655 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -265,6 +265,10 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) var_hash = next; } + (*var_hashx)->last = &(*var_hashx)->entries; + (*var_hashx)->entries.used_slots = 0; + (*var_hashx)->entries.next = NULL; + while (var_dtor_hash) { for (i = 0; i < var_dtor_hash->used_slots; i++) { zval *zv = &var_dtor_hash->data[i]; @@ -322,6 +326,13 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) var_dtor_hash = next; } + var_hash = (*var_hashx)->entries.next; + while (var_hash) { + next = var_hash->next; + efree_size(var_hash, sizeof(var_entries)); + var_hash = next; + } + if ((*var_hashx)->ref_props) { zend_hash_destroy((*var_hashx)->ref_props); FREE_HASHTABLE((*var_hashx)->ref_props);