From b6bbe33f0555a9f5a2085b1716659a94232fe0da Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 2 Mar 2016 15:09:04 +0300 Subject: [PATCH] Better fix for IS_INDIRECT support in zend_hash_merge() --- Zend/zend_hash.c | 72 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 1ffaff0361..39e9e14024 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -571,12 +571,25 @@ static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_s zval *data; if (flag & HASH_ADD) { - return NULL; - } - ZEND_ASSERT(&p->val != pData); - data = &p->val; - if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) { - data = Z_INDIRECT_P(data); + if (!(flag & HASH_UPDATE_INDIRECT)) { + return NULL; + } + ZEND_ASSERT(&p->val != pData); + data = &p->val; + if (Z_TYPE_P(data) == IS_INDIRECT) { + data = Z_INDIRECT_P(data); + if (Z_TYPE_P(data) != IS_UNDEF) { + return NULL; + } + } else { + return NULL; + } + } else { + ZEND_ASSERT(&p->val != pData); + data = &p->val; + if ((flag & HASH_UPDATE_INDIRECT) && Z_TYPE_P(data) == IS_INDIRECT) { + data = Z_INDIRECT_P(data); + } } HANDLE_BLOCK_INTERRUPTIONS(); if (ht->pDestructor) { @@ -1869,31 +1882,42 @@ ZEND_API void ZEND_FASTCALL _zend_hash_merge(HashTable *target, HashTable *sourc IS_CONSISTENT(target); HT_ASSERT(GC_REFCOUNT(target) == 1); - for (idx = 0; idx < source->nNumUsed; idx++) { - p = source->arData + idx; - if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue; - if (p->key) { - if (EXPECTED((t = zend_hash_find_ind(target, p->key)) == NULL)) { - t = zend_hash_update_ind(target, p->key, &p->val); + if (overwrite) { + for (idx = 0; idx < source->nNumUsed; idx++) { + p = source->arData + idx; + if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue; + if (UNEXPECTED(Z_TYPE(p->val) == IS_INDIRECT) && + UNEXPECTED(Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF)) { + continue; + } + if (p->key) { + t = _zend_hash_add_or_update_i(target, p->key, &p->val, HASH_UPDATE | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_RELAY_CC); if (t && pCopyConstructor) { pCopyConstructor(t); } } else { - if (!overwrite) { - continue; - } - if (target->pDestructor) { - target->pDestructor(t); - } - ZVAL_COPY_VALUE(t, &p->val); - if (pCopyConstructor) { + t = zend_hash_index_update(target, p->h, &p->val); + if (t && pCopyConstructor) { pCopyConstructor(t); } } - } else { - if ((overwrite || !zend_hash_index_exists(target, p->h))) { - t = zend_hash_index_update(target, p->h, &p->val); - if (t && pCopyConstructor) { + } + } else { + for (idx = 0; idx < source->nNumUsed; idx++) { + p = source->arData + idx; + if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue; + if (UNEXPECTED(Z_TYPE(p->val) == IS_INDIRECT) && + UNEXPECTED(Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF)) { + continue; + } + if (p->key) { + t = _zend_hash_add_or_update_i(target, p->key, &p->val, HASH_ADD | HASH_UPDATE_INDIRECT ZEND_FILE_LINE_RELAY_CC); + if (t && pCopyConstructor) { + pCopyConstructor(t); + } + } else { + t = zend_hash_index_add(target, p->h, &p->val); + if (t && pCopyConstructor) { pCopyConstructor(t); } } -- 2.40.0