Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Zend/tests/nullsafe_operator/gh23979.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
GH-23979 (Nullsafe operator must not flush delayed oplines of an enclosing function)
--FILE--
<?php
function test($name) {
$arr = ['foo' => 'bar'];
return ${$name}[(function () {
return A . B?->prop;
})()];
}
const A = 'foo';
const B = null;
var_dump(test('arr'));
?>
--EXPECT--
string(3) "bar"
4 changes: 3 additions & 1 deletion Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -3155,6 +3155,7 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
/* We will throw if $this doesn't exist, so there's no need to emit a JMP_NULL
* check for a nullsafe access. */
} else {
uint32_t offset = zend_delayed_compile_begin();
zend_short_circuiting_mark_inner(obj_ast);
opline = zend_delayed_compile_var(&obj_node, obj_ast, type, 0);
if (opline && (opline->opcode == ZEND_FETCH_DIM_W
Expand All @@ -3173,7 +3174,8 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
uint32_t count = zend_stack_count(&CG(delayed_oplines_stack));
uint32_t i = count;

while (i > 0 && oplines[i-1].result_type == IS_TMP_VAR && oplines[i-1].result.var == var) {
/* Only consider the oplines delayed while compiling obj_ast. */
while (i > offset && oplines[i-1].result_type == IS_TMP_VAR && oplines[i-1].result.var == var) {
i--;
if (oplines[i].op1_type == IS_TMP_VAR) {
var = oplines[i].op1.var;
Expand Down
Loading