From: Nikita Popov Date: Mon, 12 Oct 2020 09:03:39 +0000 (+0200) Subject: Deindirect source elements in zend_hash_merge X-Git-Tag: php-7.3.24RC1~6 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e304468e57692d4dfcf283346dd67c3e418e1934;p=php Deindirect source elements in zend_hash_merge If the RHS has INDIRECT elements, we do not those to be added to the LHS verbatim. As we're using UPDATE_INDIRECT, we might even create a nested INDIRECT that way. This is a side-quest of oss-fuzz #26245. --- diff --git a/Zend/tests/array_add_indirect.phpt b/Zend/tests/array_add_indirect.phpt new file mode 100644 index 0000000000..821cc475b9 --- /dev/null +++ b/Zend/tests/array_add_indirect.phpt @@ -0,0 +1,16 @@ +--TEST-- +Array addition should not add INDIRECT elements +--FILE-- + 1]; +$ary += $GLOBALS; +var_dump($ary['x']); +$x = 2; +var_dump($ary['x']); + +?> +--EXPECT-- +int(1) +int(1) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 2fb0eac448..7ba4f32c4d 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1999,7 +1999,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_merge(HashTable *target, HashTable *source { uint32_t idx; Bucket *p; - zval *t; + zval *t, *s; IS_CONSISTENT(source); IS_CONSISTENT(target); @@ -2008,18 +2008,20 @@ ZEND_API void ZEND_FASTCALL zend_hash_merge(HashTable *target, HashTable *source 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; + s = &p->val; + if (UNEXPECTED(Z_TYPE_P(s) == IS_INDIRECT)) { + s = Z_INDIRECT_P(s); + } + if (UNEXPECTED(Z_TYPE_P(s) == IS_UNDEF)) { + continue; } if (p->key) { - t = _zend_hash_add_or_update_i(target, p->key, &p->val, HASH_UPDATE | HASH_UPDATE_INDIRECT); + t = _zend_hash_add_or_update_i(target, p->key, s, HASH_UPDATE | HASH_UPDATE_INDIRECT); if (pCopyConstructor) { pCopyConstructor(t); } } else { - t = zend_hash_index_update(target, p->h, &p->val); + t = zend_hash_index_update(target, p->h, s); if (pCopyConstructor) { pCopyConstructor(t); } @@ -2028,18 +2030,20 @@ ZEND_API void ZEND_FASTCALL zend_hash_merge(HashTable *target, HashTable *source } 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; + s = &p->val; + if (UNEXPECTED(Z_TYPE_P(s) == IS_INDIRECT)) { + s = Z_INDIRECT_P(s); + } + if (UNEXPECTED(Z_TYPE_P(s) == IS_UNDEF)) { + continue; } if (p->key) { - t = _zend_hash_add_or_update_i(target, p->key, &p->val, HASH_ADD | HASH_UPDATE_INDIRECT); + t = _zend_hash_add_or_update_i(target, p->key, s, HASH_ADD | HASH_UPDATE_INDIRECT); if (t && pCopyConstructor) { pCopyConstructor(t); } } else { - t = zend_hash_index_add(target, p->h, &p->val); + t = zend_hash_index_add(target, p->h, s); if (t && pCopyConstructor) { pCopyConstructor(t); }