From 0df45476fc29336d7d3540e6b38b7559e8204a0b 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 1/3] 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. --- ext/opcache/jit/zend_jit_ir.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 110d84d3a343..fc9b9136948c 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -8675,7 +8675,9 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co // JIT: Z_CE(call->This) = called_scope; ir_STORE(jit_CALL(rx, This), IR_NULL); } else { - ir_ref object_or_called_scope, call_info, call_info2, object, if_cond; + ir_ref object_or_called_scope, call_info, call_info2, object; + ir_ref if_cond = IR_UNUSED; + ir_ref if_cond_user = IR_UNUSED; if (opline->op2_type == IS_CV) { // JIT: GC_ADDREF(closure); @@ -8713,15 +8715,28 @@ 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); + } + + if (!func || func->common.type == ZEND_USER_FUNCTION) { + // 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); + + // 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))); - // 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); + } - 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; From b1d00191f7dbf54b9335c3e7501c4f9918a5978a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 20 Feb 2025 22:44:47 +0100 Subject: [PATCH 2/3] minimize diff --- ext/opcache/jit/zend_jit_ir.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index fc9b9136948c..50ef62cc2342 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -8675,8 +8675,7 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co // JIT: Z_CE(call->This) = called_scope; ir_STORE(jit_CALL(rx, This), IR_NULL); } else { - ir_ref object_or_called_scope, call_info, call_info2, object; - ir_ref if_cond = IR_UNUSED; + 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) { @@ -8726,7 +8725,7 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co // 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); - + // 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))); From b478f33b4041d90441e5ed9f92206ad64dea9110 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 21 Feb 2025 09:19:28 +0100 Subject: [PATCH 3/3] remove extra check --- ext/opcache/jit/zend_jit_ir.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 50ef62cc2342..b7841fd1701a 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -8722,15 +8722,9 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co } if (!func || func->common.type == ZEND_USER_FUNCTION) { - // 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); - // 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) {