Commit cb3579dc7a0 for php.net

commit cb3579dc7a057b5fcfbd685a941fc2d7f5324a0d
Author: Arnaud Le Blanc <365207+arnaud-lb@users.noreply.github.com>
Date:   Fri Sep 4 16:45:40 2026 +0200

    Fix zend_jit_trace_find_init_fcall_op() (#23449)

    zend_jit_trace_find_init_fcall_op() tries to find the INIT_FCALL opline
    corresponding to a ZEND_JIT_TRACE_INIT_CALL record, but it fails to do so in the
    ZEND_JIT_TRACE_FAKE_INIT_CALL case, for nested calls.

    The first loop is supposed to find the first opline after the sequence of
    ZEND_JIT_TRACE_INIT_CALL record, but it mistakenly decrements 'p' after
    initially incrementing it. As a result 'p' eventually points to an invalid
    record.

    It works for non-nested calls because the 'p->op == ZEND_JIT_TRACE_VM' condition
    is true on the first iteration in that case.

    This can not lead to a crash or miscompilations, but this results in lost
    optimization opportunities.

diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c
index 49b8e29c187..5408b29fc4e 100644
--- a/ext/opcache/jit/zend_jit_trace.c
+++ b/ext/opcache/jit/zend_jit_trace.c
@@ -1167,6 +1167,9 @@ static const zend_op *zend_jit_trace_find_init_fcall_op(zend_jit_trace_rec *p, c
 		const zend_op *opline = NULL;
 		int call_level = 0;

+		/* Scan trace buffer forward to find the first recorded opline after
+		 * the sequence of ZEND_JIT_TRACE_INIT_CALL, and keep track of the
+		 * call level. */
 		p++;
 		while (1) {
 			if (p->op == ZEND_JIT_TRACE_VM) {
@@ -1178,8 +1181,9 @@ static const zend_op *zend_jit_trace_find_init_fcall_op(zend_jit_trace_rec *p, c
 			} else {
 				return NULL;
 			}
-			p--;
+			p++;
 		}
+		/* Scan oplines backward to find the init fcall op */
 		if (opline) {
 			while (opline > op_array->opcodes) {
 				opline--;