From 511eea83cdf90a3f4402f85a2b980885a584cac3 Mon Sep 17 00:00:00 2001 From: ndossche <7771979+ndossche@users.noreply.github.com> Date: Sat, 17 Oct 2026 21:54:00 +0200 Subject: [PATCH] Fix GH-24386: JIT: register operand must be loaded before the typed reference check When the left side of a compound assignment may be a ref, the JIT adds a ref type check. The typed-reference path calls a helper that doesn't load the right hand side of the compound assignment. That's in contrast to the normal path that does put it in a register. If the typed ref path doesn't load, then the value remains undefined. --- ext/opcache/jit/zend_jit_ir.c | 7 ++++++ ext/opcache/tests/jit/gh24386.phpt | 34 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 ext/opcache/tests/jit/gh24386.phpt diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 92a068dbfaca..bbadfc62b76e 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -6276,6 +6276,13 @@ static int zend_jit_assign_op(zend_jit_ctx *jit, ir_ref if_op1_typed = IR_UNUSED; binary_op_type binary_op = get_binary_op(opline->extended_value); + if (Z_MODE(op2_addr) == IS_REG + && Z_LOAD(op2_addr) + && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) { + /* Force load, so that the register is defined on all paths */ + zend_jit_use_reg(jit, op2_addr); + } + ref = jit_ZVAL_ADDR(jit, op1_addr); if_op1_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE)); ir_IF_FALSE(if_op1_ref); diff --git a/ext/opcache/tests/jit/gh24386.phpt b/ext/opcache/tests/jit/gh24386.phpt new file mode 100644 index 000000000000..cbf540b6bab5 --- /dev/null +++ b/ext/opcache/tests/jit/gh24386.phpt @@ -0,0 +1,34 @@ +--TEST-- +GH-24386 (register operand must be loaded before the typed reference check) +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=tracing +opcache.jit_hot_func=2 +--FILE-- +prop; +f(3); +var_dump($c->prop, $h); +?> +--EXPECT-- +int(2) +int(2) +int(3) +int(5)