Skip to content

Commit 91734fc

Browse files
committed
Merge branch 'PHP-8.1'
* PHP-8.1: Fix crush after compilation of nullsafe operator introduced in 307e476
2 parents 9c6b843 + 7e08018 commit 91734fc

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed

Zend/tests/bug81216_2.phpt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
Bug #81216_2: Nullsafe operator leaks dynamic property name
3+
--FILE--
4+
<?php
5+
$a = [null];
6+
$a[1] = $a[0]?->x;
7+
var_dump($a);
8+
?>
9+
--EXPECT--
10+
array(2) {
11+
[0]=>
12+
NULL
13+
[1]=>
14+
NULL
15+
}

Zend/zend_compile.c

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,9 +2179,11 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */
21792179

21802180
ZEND_ASSERT(count >= offset);
21812181
for (i = offset; i < count; ++i) {
2182-
if (oplines[i].opcode != ZEND_NOP) {
2182+
if (EXPECTED(oplines[i].opcode != ZEND_NOP)) {
21832183
opline = get_next_op();
21842184
memcpy(opline, &oplines[i], sizeof(zend_op));
2185+
} else {
2186+
opline = CG(active_op_array)->opcodes + oplines[i].extended_value;
21852187
}
21862188
}
21872189

@@ -2825,15 +2827,28 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
28252827

28262828
zend_separate_if_call_and_write(&obj_node, obj_ast, type);
28272829
if (nullsafe) {
2828-
/* Flush delayed oplines */
2829-
zend_op *opline = NULL, *oplines = zend_stack_base(&CG(delayed_oplines_stack));
2830-
uint32_t i, count = zend_stack_count(&CG(delayed_oplines_stack));
2831-
2832-
for (i = 0; i < count; ++i) {
2833-
if (oplines[i].opcode != ZEND_NOP) {
2834-
opline = get_next_op();
2835-
memcpy(opline, &oplines[i], sizeof(zend_op));
2836-
oplines[i].opcode = ZEND_NOP;
2830+
if (obj_node.op_type == IS_TMP_VAR) {
2831+
/* Flush delayed oplines */
2832+
zend_op *opline = NULL, *oplines = zend_stack_base(&CG(delayed_oplines_stack));
2833+
uint32_t var = obj_node.u.op.var;
2834+
uint32_t count = zend_stack_count(&CG(delayed_oplines_stack));
2835+
uint32_t i = count;
2836+
2837+
while (i > 0 && oplines[i-1].result_type == IS_TMP_VAR && oplines[i-1].result.var == var) {
2838+
i--;
2839+
if (oplines[i].op1_type == IS_TMP_VAR) {
2840+
var = oplines[i].op1.var;
2841+
} else {
2842+
break;
2843+
}
2844+
}
2845+
for (; i < count; ++i) {
2846+
if (oplines[i].opcode != ZEND_NOP) {
2847+
opline = get_next_op();
2848+
memcpy(opline, &oplines[i], sizeof(zend_op));
2849+
oplines[i].opcode = ZEND_NOP;
2850+
oplines[i].extended_value = opline - CG(active_op_array)->opcodes;
2851+
}
28372852
}
28382853
}
28392854
zend_emit_jmp_null(&obj_node);

0 commit comments

Comments
 (0)