Commit a1975b108bb for php
commit a1975b108bb376585ad4f1033219e00649214843
Author: waroad <dohanam2@illinois.edu>
Date: Mon Oct 19 22:11:35 2026 -0500
JIT: Fix OP_DATA read from an unwritten slot in zend_jit_assign_dim_op()
The typed-reference branch spilled OP_DATA to its stack slot and then set
op3_addr to that slot, so the code emitted after the branch also read
OP_DATA from the slot, which is only written on the typed-reference path.
Pass the slot to zend_jit_assign_op_to_typed_ref() only, as
zend_jit_assign_op() does.
Assisted-by: Claude
Closes GH-24451.
diff --git a/NEWS b/NEWS
index 5f966a6ea0f..d4325d008a6 100644
--- a/NEWS
+++ b/NEWS
@@ -81,6 +81,8 @@ PHP NEWS
is reloaded from memory). (ndossche)
. Fixed bug GH-24386 (JIT: register operand must be loaded before the typed
reference check). (ndossche)
+ . Fixed bug GH-24437 (JIT: Fix OP_DATA read from an unwritten slot in
+ zend_jit_assign_dim_op()). (waroad)
- PDO:
. Fixed invalid ATTR_ORACLE_NULLS values being accepted and truncated.
diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c
index 947e87f09cb..4c574a39a15 100644
--- a/ext/opcache/jit/zend_jit_ir.c
+++ b/ext/opcache/jit/zend_jit_ir.c
@@ -13577,9 +13577,10 @@ static int zend_jit_assign_dim_op(zend_jit_ctx *jit,
if (!zend_jit_spill_store_inv(jit, op3_addr, real_addr, op1_data_info)) {
return 0;
}
- op3_addr = real_addr;
+ arg2 = jit_ZVAL_ADDR(jit, real_addr);
+ } else {
+ arg2 = jit_ZVAL_ADDR(jit, op3_addr);
}
- arg2 = jit_ZVAL_ADDR(jit, op3_addr);
ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
reference, arg2, ir_CONST_FC_FUNC(binary_op));
diff --git a/ext/opcache/tests/jit/gh24437.phpt b/ext/opcache/tests/jit/gh24437.phpt
new file mode 100644
index 00000000000..35b25e0d4aa
--- /dev/null
+++ b/ext/opcache/tests/jit/gh24437.phpt
@@ -0,0 +1,50 @@
+--TEST--
+GH-24437 (JIT: tracing JIT gives wrong sum for `$a[0] += $i + 1` on an array parameter in a loop)
+--EXTENSIONS--
+opcache
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.jit=tracing
+--FILE--
+<?php
+class C {
+ public int $prop = 10;
+}
+
+function f($a) {
+ for ($i = 0; $i < 3; $i++) {
+ @$a[0] += $i + 1;
+ }
+ return $a[0];
+}
+
+function g(array $a) {
+ for ($i = 0; $i < 3; $i++) {
+ $a[0] += $i + 1;
+ }
+ return $a[0];
+}
+
+function h($a) {
+ for ($i = 0; $i < 3; $i++) {
+ $a[2] %= $i + 1;
+ $x = $a[0] %= 1;
+ }
+}
+
+var_dump(f([1 => 2]));
+$x = 10;
+var_dump(g([&$x]), $x);
+$c = new C;
+var_dump(g([&$c->prop]), $c->prop);
+@h([]);
+?>
+DONE
+--EXPECT--
+int(6)
+int(16)
+int(16)
+int(16)
+int(16)
+DONE