Skip to content

Commit 55aadc6

Browse files
committed
Fix self-assign evaluation order for ASSIGN_DIM_OP
For $ary[idx] op= $ary we should evaluate the RHS operand first, otherwise we may create a reference-free recursive array. Use the same handling we do for the normal $ary[idx] = $ary case. Fixes oss-fuzz #40287.
1 parent a4ed171 commit 55aadc6

File tree

3 files changed

+41
-30
lines changed

3 files changed

+41
-30
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Compound array assignment with same variable
3+
--FILE--
4+
<?php
5+
function test() {
6+
$ary = [[]];
7+
$ary[0] += $ary;
8+
foreach ($ary as $v) {
9+
var_dump($v);
10+
}
11+
}
12+
test();
13+
?>
14+
--EXPECT--
15+
array(1) {
16+
[0]=>
17+
array(0) {
18+
}
19+
}

Zend/zend_compile.c

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3152,6 +3152,22 @@ static bool zend_is_assign_to_self(zend_ast *var_ast, zend_ast *expr_ast) /* {{{
31523152
}
31533153
/* }}} */
31543154

3155+
static void zend_compile_expr_with_potential_assign_to_self(
3156+
znode *expr_node, zend_ast *expr_ast, zend_ast *var_ast) {
3157+
if (zend_is_assign_to_self(var_ast, expr_ast) && !is_this_fetch(expr_ast)) {
3158+
/* $a[0] = $a should evaluate the right $a first */
3159+
znode cv_node;
3160+
3161+
if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) {
3162+
zend_compile_simple_var_no_cv(expr_node, expr_ast, BP_VAR_R, 0);
3163+
} else {
3164+
zend_emit_op_tmp(expr_node, ZEND_QM_ASSIGN, &cv_node, NULL);
3165+
}
3166+
} else {
3167+
zend_compile_expr(expr_node, expr_ast);
3168+
}
3169+
}
3170+
31553171
static void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
31563172
{
31573173
zend_ast *var_ast = ast->child[0];
@@ -3192,20 +3208,7 @@ static void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
31923208
case ZEND_AST_DIM:
31933209
offset = zend_delayed_compile_begin();
31943210
zend_delayed_compile_dim(result, var_ast, BP_VAR_W);
3195-
3196-
if (zend_is_assign_to_self(var_ast, expr_ast)
3197-
&& !is_this_fetch(expr_ast)) {
3198-
/* $a[0] = $a should evaluate the right $a first */
3199-
znode cv_node;
3200-
3201-
if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) {
3202-
zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0);
3203-
} else {
3204-
zend_emit_op_tmp(&expr_node, ZEND_QM_ASSIGN, &cv_node, NULL);
3205-
}
3206-
} else {
3207-
zend_compile_expr(&expr_node, expr_ast);
3208-
}
3211+
zend_compile_expr_with_potential_assign_to_self(&expr_node, expr_ast, var_ast);
32093212

32103213
opline = zend_delayed_compile_end(offset);
32113214
opline->opcode = ZEND_ASSIGN_DIM;
@@ -3375,7 +3378,7 @@ static void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */
33753378
case ZEND_AST_DIM:
33763379
offset = zend_delayed_compile_begin();
33773380
zend_delayed_compile_dim(result, var_ast, BP_VAR_RW);
3378-
zend_compile_expr(&expr_node, expr_ast);
3381+
zend_compile_expr_with_potential_assign_to_self(&expr_node, expr_ast, var_ast);
33793382

33803383
opline = zend_delayed_compile_end(offset);
33813384
opline->opcode = ZEND_ASSIGN_DIM_OP;
@@ -8962,17 +8965,8 @@ static void zend_compile_assign_coalesce(znode *result, zend_ast *ast) /* {{{ */
89628965
zend_emit_op_tmp(result, ZEND_COALESCE, &var_node_is, NULL);
89638966

89648967
CG(memoize_mode) = ZEND_MEMOIZE_NONE;
8965-
if (var_ast->kind == ZEND_AST_DIM
8966-
&& zend_is_assign_to_self(var_ast, default_ast)
8967-
&& !is_this_fetch(default_ast)) {
8968-
/* $a[0] = $a should evaluate the right $a first */
8969-
znode cv_node;
8970-
8971-
if (zend_try_compile_cv(&cv_node, default_ast) == FAILURE) {
8972-
zend_compile_simple_var_no_cv(&default_node, default_ast, BP_VAR_R, 0);
8973-
} else {
8974-
zend_emit_op_tmp(&default_node, ZEND_QM_ASSIGN, &cv_node, NULL);
8975-
}
8968+
if (var_ast->kind == ZEND_AST_DIM) {
8969+
zend_compile_expr_with_potential_assign_to_self(&default_node, default_ast, var_ast);
89768970
} else {
89778971
zend_compile_expr(&default_node, default_ast);
89788972
}

ext/opcache/tests/jit/assign_dim_op_004.phpt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@ $a = null;
1111
$a[] .= $a;
1212
var_dump($a);
1313
?>
14-
--EXPECTF--
15-
Warning: Array to string conversion in %sassign_dim_op_004.php on line 3
14+
--EXPECT--
1615
array(1) {
1716
[0]=>
18-
string(5) "Array"
17+
string(0) ""
1918
}
20-

0 commit comments

Comments
 (0)