Skip to content

Commit c4f56c5

Browse files
committed
Merge branch 'PHP-8.1' into PHP-8.2
* PHP-8.1: Fix add_function_array() assertion when op2 contains op1
2 parents dd29b66 + 84b4020 commit c4f56c5

File tree

4 files changed

+61
-6
lines changed

4 files changed

+61
-6
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ PHP NEWS
66
. Fix inconsistent float negation in constant expressions. (ilutov)
77
. Fixed bug GH-8841 (php-cli core dump calling a badly formed function).
88
(nielsdos)
9+
. Fixed bug GH-10085 (Assertion when adding two arrays with += where the first
10+
array is contained in the second). (ilutov)
911

1012
- DOM:
1113
. Fixed bug #80602 (Segfault when using DOMChildNode::before()).

Zend/tests/gh10085_1.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
GH-10085: Assertion in add_function_array()
3+
--FILE--
4+
<?php
5+
$i = [[], 0];
6+
$ref = &$i;
7+
$i[0] += $ref;
8+
var_dump($i);
9+
?>
10+
--EXPECT--
11+
array(2) {
12+
[0]=>
13+
array(2) {
14+
[0]=>
15+
array(0) {
16+
}
17+
[1]=>
18+
int(0)
19+
}
20+
[1]=>
21+
int(0)
22+
}

Zend/tests/gh10085_2.phpt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
GH-10085: Assertion in add_function_array()
3+
--FILE--
4+
<?php
5+
$tmp = [0];
6+
unset($tmp[0]);
7+
$i = [$tmp, 0];
8+
unset($tmp);
9+
$ref = &$i;
10+
$i[0] += $ref;
11+
var_dump($i);
12+
?>
13+
--EXPECT--
14+
array(2) {
15+
[0]=>
16+
array(2) {
17+
[0]=>
18+
array(0) {
19+
}
20+
[1]=>
21+
int(0)
22+
}
23+
[1]=>
24+
int(0)
25+
}

Zend/zend_operators.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,16 +1015,22 @@ static ZEND_COLD zend_never_inline void ZEND_FASTCALL zend_binop_error(const cha
10151015

10161016
static zend_never_inline void ZEND_FASTCALL add_function_array(zval *result, zval *op1, zval *op2) /* {{{ */
10171017
{
1018-
if (result == op1 && Z_ARR_P(op1) == Z_ARR_P(op2)) {
1019-
/* $a += $a */
1020-
return;
1021-
}
10221018
if (result != op1) {
10231019
ZVAL_ARR(result, zend_array_dup(Z_ARR_P(op1)));
1020+
zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
1021+
} else if (Z_ARR_P(op1) == Z_ARR_P(op2)) {
1022+
/* $a += $a */
10241023
} else {
1025-
SEPARATE_ARRAY(result);
1024+
/* We have to duplicate op1 (even with refcount == 1) because it may be an element of op2
1025+
* and therefore its reference counter may be increased by zend_hash_merge(). That leads to
1026+
* an assertion in _zend_hash_add_or_update_i() that only allows adding elements to hash
1027+
* tables with RC1. See GH-10085 and Zend/tests/gh10085*.phpt */
1028+
zval tmp;
1029+
ZVAL_ARR(&tmp, zend_array_dup(Z_ARR_P(op1)));
1030+
zend_hash_merge(Z_ARRVAL(tmp), Z_ARRVAL_P(op2), zval_add_ref, 0);
1031+
zval_ptr_dtor(result);
1032+
ZVAL_COPY_VALUE(result, &tmp);
10261033
}
1027-
zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
10281034
}
10291035
/* }}} */
10301036

0 commit comments

Comments
 (0)