From 6948c83719d94efac9bac43d765dd0cb3d64702c Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Mon, 26 Oct 2026 09:42:16 +0100 Subject: [PATCH 1/4] Destructor of regular arrays must be ZVAL_PTR_DTOR or NULL --- Zend/zend_hash.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index dc4c7a6c91dd..a8a3f9159dff 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -2051,6 +2051,9 @@ ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht) if (ht->nNumUsed) { /* In some rare cases destructors of regular arrays may be changed */ if (UNEXPECTED(ht->pDestructor != ZVAL_PTR_DTOR)) { + if (UNEXPECTED(ht->pDestructor != NULL)) { + abort(); + } zend_hash_destroy(ht); goto free_ht; } From 64cff0b9f9f4941050cef62f9db10b39ecf69638 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Mon, 26 Oct 2026 10:39:35 +0100 Subject: [PATCH 2/4] Avoid using zend_array_destroy for a non-array HashTable --- ext/dom/private_data.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ext/dom/private_data.c b/ext/dom/private_data.c index dd624a2c2e9c..55d1fb5b43a3 100644 --- a/ext/dom/private_data.c +++ b/ext/dom/private_data.c @@ -42,6 +42,14 @@ php_dom_libxml_ns_mapper *php_dom_ns_mapper_from_private(php_dom_private_data *p return private_data == NULL ? NULL : &private_data->ns_mapper; } +static void php_dom_libxml_ns_mapper_prefix_map_dtor(zval *zv) +{ + HashTable *ht = Z_ARRVAL_P(zv); + + zend_hash_destroy(ht); + efree(ht); +} + php_dom_private_data *php_dom_private_data_create(void) { php_dom_private_data *private_data = emalloc(sizeof(*private_data)); @@ -49,7 +57,7 @@ php_dom_private_data *php_dom_private_data_create(void) private_data->header.ns_hook = php_dom_libxml_private_data_ns_hook; private_data->ns_mapper.html_ns = NULL; private_data->ns_mapper.prefixless_xmlns_ns = NULL; - zend_hash_init(&private_data->ns_mapper.uri_to_prefix_map, 0, NULL, ZVAL_PTR_DTOR, false); + zend_hash_init(&private_data->ns_mapper.uri_to_prefix_map, 0, NULL, php_dom_libxml_ns_mapper_prefix_map_dtor, false); private_data->template_fragments = NULL; return private_data; } From d9e7129d5778abef7d54bed68a982909e408279a Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Mon, 26 Oct 2026 11:12:17 +0100 Subject: [PATCH 3/4] Use zend_new_array() for HashTable exposed to userspace --- ext/mbstring/mbstring.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 263b4561a67a..986aac3d8195 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -3570,8 +3570,7 @@ PHP_FUNCTION(mb_list_encodings) /* Initialize shared array of supported encoding names * This is done so that we can check if `mb_list_encodings()` is being * passed to other mbstring functions using a cheap pointer equality check */ - HashTable *array = emalloc(sizeof(HashTable)); - zend_hash_init(array, 80, NULL, zval_ptr_dtor_str, false); + HashTable *array = zend_new_array(80); for (const mbfl_encoding **encodings = mbfl_get_supported_encodings(); *encodings; encodings++) { zval tmp; ZVAL_STRING(&tmp, (*encodings)->name); From 6877ae60598cf98a0c1e080f409ce0d0f44a0bc5 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Mon, 26 Oct 2026 11:21:14 +0100 Subject: [PATCH 4/4] [ci skip] UPGRADING --- UPGRADING.INTERNALS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 4c5d74b49e9c..ba5768f0f5dc 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -47,6 +47,10 @@ PHP 8.7 INTERNALS UPGRADE NOTES - The INIT_CLASS_ENTRY_INIT_METHODS() macro, which was previously used as part of handling disabled classes, was removed following the removal of the `disable_classes` INI setting in PHP 8.5. +- Using zend_array_destroy() on HashTables with a custom pDestructor is not + allowed anymore. User-facing HashTables must have pDestructor = ZVAL_PTR_DTOR + or NULL, and must be freed with zend_array_destroy(). Other HashTables can be + freed with zend_hash_destroy() + pefree(). ======================== 2. Build system changes