Commit e31268f3de4 for php
commit e31268f3de45740aeec39c02d5489571cad3ef28
Author: ndossche <7771979+ndossche@users.noreply.github.com>
Date: Sat Oct 17 21:54:00 2026 +0200
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.
Closes GH-24387.
diff --git a/NEWS b/NEWS
index 417fa0b71f2..4d970852134 100644
--- a/NEWS
+++ b/NEWS
@@ -79,6 +79,8 @@ PHP NEWS
case 0). (ndossche)
. Fixed bug GH-24206 (Tracing JIT loses loop-carried CV when its loop PHI
is reloaded from memory). (ndossche)
+ . Fixed bug GH-24386 (JIT: register operand must be loaded before the typed
+ reference check). (ndossche)
- PDO:
. Fixed a duplicate warning when ATTR_STATEMENT_CLASS is rejected on a
diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c
index 236192c9933..947e87f09cb 100644
--- a/ext/opcache/jit/zend_jit_ir.c
+++ b/ext/opcache/jit/zend_jit_ir.c
@@ -6285,6 +6285,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 00000000000..cbf540b6bab
--- /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--
+<?php
+class C {
+ public int $prop = 0;
+}
+
+function f($n) {
+ global $g, $h;
+ $g += $n;
+ $h += $n;
+}
+
+f(2);
+var_dump($g, $h);
+
+$c = new C;
+$g =& $c->prop;
+f(3);
+var_dump($c->prop, $h);
+?>
+--EXPECT--
+int(2)
+int(2)
+int(3)
+int(5)