diff --git a/NEWS b/NEWS index a2ac73a1c5a..218f01d3a1a 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) - Curl: . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead 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 cebb3258aef..1f6f992f279 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -2465,6 +2465,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; @@ -2481,6 +2482,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; @@ -2500,7 +2502,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 =