]> granicus.if.org Git - php/commitdiff
Deindirect source elements in zend_hash_merge
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 12 Oct 2020 09:03:39 +0000 (11:03 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 12 Oct 2020 09:24:27 +0000 (11:24 +0200)
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.

Zend/tests/array_add_indirect.phpt [new file with mode: 0644]
Zend/zend_hash.c

diff --git a/Zend/tests/array_add_indirect.phpt b/Zend/tests/array_add_indirect.phpt
new file mode 100644 (file)
index 0000000..821cc47
--- /dev/null
@@ -0,0 +1,16 @@
+--TEST--
+Array addition should not add INDIRECT elements
+--FILE--
+<?php
+
+$x = 1;
+$ary = ['y' => 1];
+$ary += $GLOBALS;
+var_dump($ary['x']);
+$x = 2;
+var_dump($ary['x']);
+
+?>
+--EXPECT--
+int(1)
+int(1)
index 2fb0eac448fdc20d5453ce0c435610f627950419..7ba4f32c4dfb9259e7889573de2560b711d68bde 100644 (file)
@@ -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);
                                }