From f045716288af47499fe5c87104e0d3db0570072d Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 15 Sep 2025 22:07:38 +0200 Subject: [PATCH] Fix incorrect HASH_FLAG_HAS_EMPTY_IND flag on userland array Fixes GH-19839 Closes GH-19851 --- NEWS | 2 ++ Zend/tests/gh19839.phpt | 18 ++++++++++++++++++ Zend/zend_hash.c | 5 ++++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh19839.phpt diff --git a/NEWS b/NEWS index 028617dfae4..0891acce266 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ PHP NEWS exception are triggered). (nielsdos) . Fixed bug GH-19653 (Closure named argument unpacking between temporary closures can cause a crash). (nielsdos, Arnaud, Bob) + . Fixed bug GH-19839 (Incorrect HASH_FLAG_HAS_EMPTY_IND flag on userland + array). (ilutov) - Date: . Fixed GH-17159: "P" format for ::createFromFormat swallows string literals. diff --git a/Zend/tests/gh19839.phpt b/Zend/tests/gh19839.phpt new file mode 100644 index 00000000000..cc589ce0605 --- /dev/null +++ b/Zend/tests/gh19839.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-19839: Incorrect HASH_FLAG_HAS_EMPTY_IND flag on userland array +--FILE-- + +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 07d5bed6d76..fdc05ff8cbf 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -2466,6 +2466,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source) target->nTableSize = HT_MIN_SIZE; HT_SET_DATA_ADDR(target, &uninitialized_bucket); } else if (GC_FLAGS(source) & IS_ARRAY_IMMUTABLE) { + ZEND_ASSERT(!(HT_FLAGS(source) & HASH_FLAG_HAS_EMPTY_IND)); HT_FLAGS(target) = HT_FLAGS(source) & HASH_FLAG_MASK; target->nTableMask = source->nTableMask; target->nNumUsed = source->nNumUsed; @@ -2482,6 +2483,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source) memcpy(HT_GET_DATA_ADDR(target), HT_GET_DATA_ADDR(source), HT_USED_SIZE(source)); } } else if (HT_IS_PACKED(source)) { + ZEND_ASSERT(!(HT_FLAGS(source) & HASH_FLAG_HAS_EMPTY_IND)); HT_FLAGS(target) = HT_FLAGS(source) & HASH_FLAG_MASK; target->nTableMask = HT_MIN_MASK; target->nNumUsed = source->nNumUsed; @@ -2501,7 +2503,8 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source) zend_array_dup_packed_elements(source, target, 1); } } else { - HT_FLAGS(target) = HT_FLAGS(source) & HASH_FLAG_MASK; + /* Indirects are removed during duplication, remove HASH_FLAG_HAS_EMPTY_IND accordingly. */ + HT_FLAGS(target) = HT_FLAGS(source) & (HASH_FLAG_MASK & ~HASH_FLAG_HAS_EMPTY_IND); target->nTableMask = source->nTableMask; target->nNextFreeElement = source->nNextFreeElement; target->nInternalPointer =