From 05afc37effb14ac3a9991891beda94285708a9ac Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Tue, 12 May 2026 15:47:27 -0400 Subject: [PATCH] JIT: Fix escape_if_undef on PHP-8.4 CALL VM Two issues in zend_jit_escape_if_undef. Register orig_handler as IR_FUNC_ADDR (was tripping the FUNC_ADDR assertion in side-trace compile); replace ir_TAILCALL_1 with ir_CALL_1 + ir_RETURN(1) so execute_ex reloads execute_data after the deopt on CALL VM. Fixes GH-21368 Closes GH-22028 --- ext/opcache/jit/zend_jit_ir.c | 8 ++--- ext/opcache/tests/jit/gh21368_call_vm.phpt | 36 ++++++++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 ext/opcache/tests/jit/gh21368_call_vm.phpt diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 1346d141754f..f99605ee4208 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -8096,14 +8096,12 @@ static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, zend_jit_op_array_trace_extension *jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array); size_t offset = jit_extension->offset; - ir_ref ref = ir_CONST_ADDR(ZEND_OP_TRACE_INFO((opline - 1), offset)->orig_handler); + ir_ref ref = ir_CONST_FC_FUNC(ZEND_OP_TRACE_INFO((opline - 1), offset)->orig_handler); if (GCC_GLOBAL_REGS) { ir_TAILCALL(IR_VOID, ref); } else { -#if defined(IR_TARGET_X86) - ref = ir_CAST_FC_FUNC(ref); -#endif - ir_TAILCALL_1(IR_I32, ref, jit_FP(jit)); + ir_CALL_1(IR_I32, ref, jit_FP(jit)); + ir_RETURN(ir_CONST_I32(1)); } ir_IF_TRUE(if_def); diff --git a/ext/opcache/tests/jit/gh21368_call_vm.phpt b/ext/opcache/tests/jit/gh21368_call_vm.phpt new file mode 100644 index 000000000000..cc64e62a610e --- /dev/null +++ b/ext/opcache/tests/jit/gh21368_call_vm.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-21368 (JIT escape_if_undef SEGV on CALL VM with aggressive trace counters) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=64M +opcache.jit=tracing +opcache.protect_memory=1 +opcache.jit_hot_loop=1 +opcache.jit_hot_func=1 +opcache.jit_hot_return=1 +opcache.jit_hot_side_exit=1 +--FILE-- +x; } +} + +$o1 = new C; +$o2 = new C; +$o2->x = false; +$o3 = new C; +unset($o3->x); +$a = [$o1, $o2, $o3]; + +for ($i = 0; $i < 8; $i++) { + $m = $a[$i % 3]; + $m->getX(); + $m->getX(); +} +?> +OK +--EXPECT-- +OK