Commit ef589ce6698 for php.net

commit ef589ce6698405721e0e061142a6192e1bf8c2b0
Author: Arnaud Le Blanc <arnaud.lb@gmail.com>
Date:   Mon May 11 13:35:28 2026 +0200

    JIT: Fix TSSA of ZEND_FE_FETCH_R with key operand

    During type inference of `foreach ($array as $key => $elem)`, in the case of
    loops that didn't iterate during tracing, we copy the use var info of $elem
    to the def, but we forgot to do the same for $key.

    Fixes GH-22004
    Closes GH-22008

diff --git a/NEWS b/NEWS
index c2767fd3c30..8dea2348ff3 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,8 @@ PHP                                                                        NEWS
 - Opcache:
   . Fixed tracing JIT crash when a VM interrupt is handled during an observed
     user function call. (Levi Morrison)
+  . Fixed bug GH-22004 (Assertion failure at ext/opcache/jit/zend_jit_trace.c).
+    (Arnaud)

 - OpenSSL:
   . Fix compatibility issues with OpenSSL 4.0. (jordikroon, Remi)
diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c
index 1237d1b7a42..da97d102f20 100644
--- a/ext/opcache/jit/zend_jit_trace.c
+++ b/ext/opcache/jit/zend_jit_trace.c
@@ -2315,6 +2315,9 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
 				if (ssa_ops[idx].op2_use >= 0 && ssa_ops[idx].op2_def >= 0) {
 					ssa_var_info[ssa_ops[idx].op2_def] = ssa_var_info[ssa_ops[idx].op2_use];
 				}
+				if (ssa_ops[idx].result_use >= 0 && ssa_ops[idx].result_def >= 0) {
+					ssa_var_info[ssa_ops[idx].result_def] = ssa_var_info[ssa_ops[idx].result_use];
+				}
 			} else {
 				if (zend_update_type_info(op_array, tssa, script, (zend_op*)opline, ssa_ops + idx, ssa_opcodes, optimization_level) == FAILURE) {
 					// TODO:
diff --git a/ext/opcache/tests/jit/gh22004.phpt b/ext/opcache/tests/jit/gh22004.phpt
new file mode 100644
index 00000000000..bb60868a269
--- /dev/null
+++ b/ext/opcache/tests/jit/gh22004.phpt
@@ -0,0 +1,63 @@
+--TEST--
+GH-22004: ZEND_FE_FETCH_R with key operand
+--CREDITS--
+YuanchengJiang
+--FILE--
+<?php
+
+function doRandom($iter) {
+    for ($i = 0; $i < $iter; $i++) {
+        $lines = [];
+        for ($j = 0; $j < $nLines; $j++) {
+            $lines[] = $line;
+        }
+        foreach ($lines as $i => $line) {
+        }
+    }
+}
+$iter = 20;
+doRandom($iter);
+
+?>
+==DONE==
+--EXPECTF--
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+
+Warning: Undefined variable $nLines in %s on line %d
+==DONE==