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--;