Commit 05afc37effb for php.net
commit 05afc37effb14ac3a9991891beda94285708a9ac
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Tue May 12 15:47:27 2026 -0400
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
diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c
index 1346d141754..f99605ee420 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 00000000000..cc64e62a610
--- /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--
+<?php
+class C {
+ public $x = true;
+ public function __get($name) { return null; }
+ public function getX() { return $this->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