Skip to content

Commit 4c71cf2

Browse files
committed
Fix GH-21368 crash: runtime lookup for orig_handler in escape_if_undef
PR #21368 replaced the trace_escape stub dispatch in zend_jit_escape_if_undef with a compile-time constant load of orig_handler, computed from the exit info's op_array pointer. That pointer can be NULL (when current_frame is NULL at exit-point creation) or stale (when the underlying op_array is freed before the side trace compiles), producing an access violation inside zend_jit_escape_if_undef. Reported on PHP 8.5.5 Windows NTS. Drop the op_array parameter and emit a runtime lookup via zend_jit_orig_opline_handler() instead. That helper resolves the jit_extension through EX(func) at dispatch time, which is valid regardless of the compile-time op_array state. The gh21267 tests still pass, confirming the infinite-loop fix is preserved.
1 parent 391ec27 commit 4c71cf2

2 files changed

Lines changed: 8 additions & 7 deletions

File tree

ext/opcache/jit/zend_jit_ir.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8068,7 +8068,7 @@ static int zend_jit_defined(zend_jit_ctx *jit, const zend_op *opline, uint8_t sm
80688068
return 1;
80698069
}
80708070

8071-
static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, const zend_op_array *op_array, int8_t reg)
8071+
static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, int8_t reg)
80728072
{
80738073
zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
80748074
ir_ref if_def = ir_IF(jit_Z_TYPE(jit, reg_addr));
@@ -8092,11 +8092,12 @@ static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags,
80928092

80938093
jit_LOAD_IP_ADDR(jit, opline - 1);
80948094

8095-
/* We can't use trace_escape() because opcode handler may be overridden by JIT */
8096-
zend_jit_op_array_trace_extension *jit_extension =
8097-
(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8098-
size_t offset = jit_extension->offset;
8099-
ir_ref ref = ir_CONST_ADDR(ZEND_OP_TRACE_INFO((opline - 1), offset)->orig_handler);
8095+
/* We can't use trace_escape() because the current opline handler may
8096+
* have been overridden by JIT code. Dispatch to orig_handler via the
8097+
* runtime lookup (EX(func) -> jit_extension -> offset), which always
8098+
* resolves even when the exit_info's op_array reference is unavailable
8099+
* or stale. */
8100+
ir_ref ref = zend_jit_orig_opline_handler(jit);
81008101
if (GCC_GLOBAL_REGS) {
81018102
ir_TAILCALL(IR_VOID, ref);
81028103
} else {

ext/opcache/jit/zend_jit_trace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3603,7 +3603,7 @@ static int zend_jit_trace_deoptimization(
36033603

36043604
ZEND_ASSERT(STACK_FLAGS(parent_stack, check2) == ZREG_ZVAL_COPY);
36053605
ZEND_ASSERT(reg != ZREG_NONE);
3606-
if (!zend_jit_escape_if_undef(jit, check2, flags, opline, exit_info->op_array, reg)) {
3606+
if (!zend_jit_escape_if_undef(jit, check2, flags, opline, reg)) {
36073607
return 0;
36083608
}
36093609
if (!zend_jit_restore_zval(jit, EX_NUM_TO_VAR(check2), reg)) {

0 commit comments

Comments
 (0)