[php-src] master: Merge branch 'PHP-8.6'

From: Date: Thu, 08 Oct 2026 17:54:36 +0000
Subject: [php-src] master: Merge branch 'PHP-8.6'
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-142101@lists.php.net to get a copy of this message
Author: ndossche (ndossche) Date: 2026-10-08T19:54:18+02:00 Commit: https://github.com/php/php-src/commit/d0f6dfe22a2ceec64529d70916c36cd6fb197402 Raw diff: https://github.com/php/php-src/commit/d0f6dfe22a2ceec64529d70916c36cd6fb197402.diff Merge branch 'PHP-8.6' * PHP-8.6: Fix GH-23979: Nullsafe operator must not flush delayed oplines of an enclosing function Changed paths: A Zend/tests/nullsafe_operator/gh23979.phpt M Zend/zend_compile.c Diff: diff --git a/Zend/tests/nullsafe_operator/gh23979.phpt b/Zend/tests/nullsafe_operator/gh23979.phpt new file mode 100644 index 000000000000..ba5e78feb1a2 --- /dev/null +++ b/Zend/tests/nullsafe_operator/gh23979.phpt @@ -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" diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index b994f3251674..dfd7497a6ed0 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2489,10 +2489,15 @@ static inline zend_op *zend_delayed_emit_op(znode *result, uint8_t opcode, znode } /* }}} */ -static inline uint32_t zend_delayed_compile_begin(void) /* {{{ */ +static zend_always_inline uint32_t zend_delayed_oplines_stack_size(void) { return zend_stack_count(&CG(delayed_oplines_stack)); } + +static inline uint32_t zend_delayed_compile_begin(void) /* {{{ */ +{ + return zend_delayed_oplines_stack_size(); +} /* }}} */ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */ @@ -3212,6 +3217,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_oplines_stack_size(); zend_short_circuiting_mark_inner(obj_ast); zend_mark_const_object_fetch(obj_ast); opline = zend_delayed_compile_var(&obj_node, obj_ast, type, false); @@ -3228,10 +3234,11 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t /* Flush delayed oplines */ zend_op *opline = NULL, *oplines = zend_stack_base(&CG(delayed_oplines_stack)); uint32_t var = obj_node.u.op.var; - uint32_t count = zend_stack_count(&CG(delayed_oplines_stack)); + uint32_t count = zend_delayed_oplines_stack_size(); 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;

« previous php.cvs (#142101) next »