From 5ede5415e102d4ed802c697f74aa7f695aa3cf27 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 20 Feb 2025 21:58:42 +0100 Subject: [PATCH] Fix GH-17868: Cannot allocate memory with tracing JIT on 8.4.4 The generated code tries to initialize the run time cache for even internal closures, but it should only initialize the run time cache for user closures. We fix this by adding a check for the function type. If `func` is known, then we can check the type at code generation time. Closes GH-17869. --- NEWS | 2 ++ ext/opcache/jit/zend_jit_ir.c | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index 69c6e954b66..e51bffbfb42 100644 --- a/NEWS +++ b/NEWS @@ -57,6 +57,8 @@ PHP NEWS FETCH_OBJ_R breaks JIT). (Dmitry, nielsdos) . Fixed bug GH-17715 (Null pointer deref in observer API when calling cases() method on preloaded enum). (Bob) + . Fixed bug GH-17868 (Cannot allocate memory with tracing JIT on 8.4.4). + (nielsdos) - PDO_SQLite: . Fixed GH-17837 ()::getColumnMeta() on unexecuted statement segfaults). diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 110d84d3a34..b7841fd1701 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -8676,6 +8676,7 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co ir_STORE(jit_CALL(rx, This), IR_NULL); } else { ir_ref object_or_called_scope, call_info, call_info2, object, if_cond; + ir_ref if_cond_user = IR_UNUSED; if (opline->op2_type == IS_CV) { // JIT: GC_ADDREF(closure); @@ -8713,15 +8714,22 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co // JIT: Z_PTR(call->This) = object_or_called_scope; ir_STORE(jit_CALL(rx, This.value.ptr), object_or_called_scope); - // JIT: if (closure->func.op_array.run_time_cache__ptr) - if_cond = ir_IF(ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.run_time_cache__ptr)))); - ir_IF_FALSE(if_cond); + if (!func) { + // JIT: if (closure->func.common.type & ZEND_USER_FUNCTION) + ir_ref type = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.type))); + if_cond_user = ir_IF(ir_AND_U8(type, ir_CONST_U8(ZEND_USER_FUNCTION))); + ir_IF_TRUE(if_cond_user); + } - // JIT: zend_jit_init_func_run_time_cache_helper(closure->func); - ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper), - ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func))); + if (!func || func->common.type == ZEND_USER_FUNCTION) { + // JIT: zend_jit_init_func_run_time_cache_helper(closure->func); + ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper), + ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func))); + } - ir_MERGE_WITH_EMPTY_TRUE(if_cond); + if (!func) { + ir_MERGE_WITH_EMPTY_FALSE(if_cond_user); + } } // JIT: ZEND_CALL_NUM_ARGS(call) = num_args;