Skip to content

Commit e304468

Browse files
committed
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.
1 parent 1ed5a2a commit e304468

File tree

2 files changed

+33
-13
lines changed

2 files changed

+33
-13
lines changed

Zend/tests/array_add_indirect.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Array addition should not add INDIRECT elements
3+
--FILE--
4+
<?php
5+
6+
$x = 1;
7+
$ary = ['y' => 1];
8+
$ary += $GLOBALS;
9+
var_dump($ary['x']);
10+
$x = 2;
11+
var_dump($ary['x']);
12+
13+
?>
14+
--EXPECT--
15+
int(1)
16+
int(1)

Zend/zend_hash.c

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,7 +1999,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_merge(HashTable *target, HashTable *source
19991999
{
20002000
uint32_t idx;
20012001
Bucket *p;
2002-
zval *t;
2002+
zval *t, *s;
20032003

20042004
IS_CONSISTENT(source);
20052005
IS_CONSISTENT(target);
@@ -2008,18 +2008,20 @@ ZEND_API void ZEND_FASTCALL zend_hash_merge(HashTable *target, HashTable *source
20082008
if (overwrite) {
20092009
for (idx = 0; idx < source->nNumUsed; idx++) {
20102010
p = source->arData + idx;
2011-
if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2012-
if (UNEXPECTED(Z_TYPE(p->val) == IS_INDIRECT) &&
2013-
UNEXPECTED(Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF)) {
2014-
continue;
2011+
s = &p->val;
2012+
if (UNEXPECTED(Z_TYPE_P(s) == IS_INDIRECT)) {
2013+
s = Z_INDIRECT_P(s);
2014+
}
2015+
if (UNEXPECTED(Z_TYPE_P(s) == IS_UNDEF)) {
2016+
continue;
20152017
}
20162018
if (p->key) {
2017-
t = _zend_hash_add_or_update_i(target, p->key, &p->val, HASH_UPDATE | HASH_UPDATE_INDIRECT);
2019+
t = _zend_hash_add_or_update_i(target, p->key, s, HASH_UPDATE | HASH_UPDATE_INDIRECT);
20182020
if (pCopyConstructor) {
20192021
pCopyConstructor(t);
20202022
}
20212023
} else {
2022-
t = zend_hash_index_update(target, p->h, &p->val);
2024+
t = zend_hash_index_update(target, p->h, s);
20232025
if (pCopyConstructor) {
20242026
pCopyConstructor(t);
20252027
}
@@ -2028,18 +2030,20 @@ ZEND_API void ZEND_FASTCALL zend_hash_merge(HashTable *target, HashTable *source
20282030
} else {
20292031
for (idx = 0; idx < source->nNumUsed; idx++) {
20302032
p = source->arData + idx;
2031-
if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
2032-
if (UNEXPECTED(Z_TYPE(p->val) == IS_INDIRECT) &&
2033-
UNEXPECTED(Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF)) {
2034-
continue;
2033+
s = &p->val;
2034+
if (UNEXPECTED(Z_TYPE_P(s) == IS_INDIRECT)) {
2035+
s = Z_INDIRECT_P(s);
2036+
}
2037+
if (UNEXPECTED(Z_TYPE_P(s) == IS_UNDEF)) {
2038+
continue;
20352039
}
20362040
if (p->key) {
2037-
t = _zend_hash_add_or_update_i(target, p->key, &p->val, HASH_ADD | HASH_UPDATE_INDIRECT);
2041+
t = _zend_hash_add_or_update_i(target, p->key, s, HASH_ADD | HASH_UPDATE_INDIRECT);
20382042
if (t && pCopyConstructor) {
20392043
pCopyConstructor(t);
20402044
}
20412045
} else {
2042-
t = zend_hash_index_add(target, p->h, &p->val);
2046+
t = zend_hash_index_add(target, p->h, s);
20432047
if (t && pCopyConstructor) {
20442048
pCopyConstructor(t);
20452049
}

0 commit comments

Comments
 (0)