Endless recursion when using + on array in foreach

This reverts commit 84b4020eb4.

Fixes GH-11171
This commit is contained in:
Ilija Tovilo 2023-05-01 13:16:13 +02:00 committed by Pierrick Charron
parent c598a92d54
commit 8340d75d17
No known key found for this signature in database
GPG key ID: 286AF1F9897469DC
4 changed files with 21 additions and 59 deletions

View file

@ -1,22 +0,0 @@
--TEST--
GH-10085: Assertion in add_function_array()
--FILE--
<?php
$i = [[], 0];
$ref = &$i;
$i[0] += $ref;
var_dump($i);
?>
--EXPECT--
array(2) {
[0]=>
array(2) {
[0]=>
array(0) {
}
[1]=>
int(0)
}
[1]=>
int(0)
}

View file

@ -1,25 +0,0 @@
--TEST--
GH-10085: Assertion in add_function_array()
--FILE--
<?php
$tmp = [0];
unset($tmp[0]);
$i = [$tmp, 0];
unset($tmp);
$ref = &$i;
$i[0] += $ref;
var_dump($i);
?>
--EXPECT--
array(2) {
[0]=>
array(2) {
[0]=>
array(0) {
}
[1]=>
int(0)
}
[1]=>
int(0)
}

15
Zend/tests/gh11171.phpt Normal file
View file

@ -0,0 +1,15 @@
--TEST--
GH-11171: Test
--FILE--
<?php
$all = ['test'];
foreach ($all as &$item) {
$all += [$item];
}
var_dump($all);
?>
--EXPECT--
array(1) {
[0]=>
&string(4) "test"
}

View file

@ -1015,22 +1015,16 @@ static ZEND_COLD zend_never_inline void ZEND_FASTCALL zend_binop_error(const cha
static zend_never_inline void ZEND_FASTCALL add_function_array(zval *result, zval *op1, zval *op2) /* {{{ */
{
if (result == op1 && Z_ARR_P(op1) == Z_ARR_P(op2)) {
/* $a += $a */
return;
}
if (result != op1) {
ZVAL_ARR(result, zend_array_dup(Z_ARR_P(op1)));
zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
} else if (Z_ARR_P(op1) == Z_ARR_P(op2)) {
/* $a += $a */
} else {
/* We have to duplicate op1 (even with refcount == 1) because it may be an element of op2
* and therefore its reference counter may be increased by zend_hash_merge(). That leads to
* an assertion in _zend_hash_add_or_update_i() that only allows adding elements to hash
* tables with RC1. See GH-10085 and Zend/tests/gh10085*.phpt */
zval tmp;
ZVAL_ARR(&tmp, zend_array_dup(Z_ARR_P(op1)));
zend_hash_merge(Z_ARRVAL(tmp), Z_ARRVAL_P(op2), zval_add_ref, 0);
zval_ptr_dtor(result);
ZVAL_COPY_VALUE(result, &tmp);
SEPARATE_ARRAY(result);
}
zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
}
/* }}} */