diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index b92c4c1174cdc..db25ed506bd15 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1552,6 +1552,8 @@ ZEND_API void zend_frameless_observed_call(zend_execute_data *execute_data) uint8_t num_args = ZEND_FLF_NUM_ARGS(opline->opcode); zend_function *fbc = ZEND_FLF_FUNC(opline); zval *result = EX_VAR(opline->result.var); + zval tmp_result; + ZVAL_NULL(&tmp_result); zend_execute_data *call = zend_vm_stack_push_call_frame_ex(zend_vm_calc_used_stack(num_args, fbc), ZEND_CALL_NESTED_FUNCTION, fbc, num_args, NULL); call->prev_execute_data = execute_data; @@ -1565,7 +1567,8 @@ ZEND_API void zend_frameless_observed_call(zend_execute_data *execute_data) EG(current_execute_data) = call; zend_observer_fcall_begin_prechecked(call, ZEND_OBSERVER_DATA(fbc)); - fbc->internal_function.handler(call, result); + fbc->internal_function.handler(call, &tmp_result); + ZVAL_COPY_VALUE(result, &tmp_result); zend_observer_fcall_end(call, result); EG(current_execute_data) = execute_data; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b710fa874af15..9f6ce56b0eb8d 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -9638,9 +9638,9 @@ ZEND_VM_HANDLER(205, ZEND_FRAMELESS_ICALL_1, ANY, UNUSED, SPEC(OBSERVER)) SAVE_OPLINE(); zval *result = EX_VAR(opline->result.var); - ZVAL_NULL(result); zval *arg1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); if (EG(exception)) { + ZVAL_NULL(result); FREE_OP1(); HANDLE_EXCEPTION(); } @@ -9651,8 +9651,11 @@ ZEND_VM_HANDLER(205, ZEND_FRAMELESS_ICALL_1, ANY, UNUSED, SPEC(OBSERVER)) } else #endif { + zval tmp_result; + ZVAL_NULL(&tmp_result); zend_frameless_function_1 function = (zend_frameless_function_1)ZEND_FLF_HANDLER(opline); - function(result, arg1); + function(&tmp_result, arg1); + ZVAL_COPY_VALUE(result, &tmp_result); } FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -9664,10 +9667,10 @@ ZEND_VM_HANDLER(206, ZEND_FRAMELESS_ICALL_2, ANY, ANY, SPEC(OBSERVER)) SAVE_OPLINE(); zval *result = EX_VAR(opline->result.var); - ZVAL_NULL(result); zval *arg1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); zval *arg2 = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); if (EG(exception)) { + ZVAL_NULL(result); FREE_OP1(); FREE_OP2(); HANDLE_EXCEPTION(); @@ -9679,8 +9682,11 @@ ZEND_VM_HANDLER(206, ZEND_FRAMELESS_ICALL_2, ANY, ANY, SPEC(OBSERVER)) } else #endif { + zval tmp_result; + ZVAL_NULL(&tmp_result); zend_frameless_function_2 function = (zend_frameless_function_2)ZEND_FLF_HANDLER(opline); - function(result, arg1, arg2); + function(&tmp_result, arg1, arg2); + ZVAL_COPY_VALUE(result, &tmp_result); } FREE_OP1(); @@ -9698,11 +9704,11 @@ ZEND_VM_HANDLER(207, ZEND_FRAMELESS_ICALL_3, ANY, ANY, SPEC(OBSERVER)) SAVE_OPLINE(); zval *result = EX_VAR(opline->result.var); - ZVAL_NULL(result); zval *arg1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); zval *arg2 = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); zval *arg3 = GET_OP_DATA_ZVAL_PTR_DEREF(BP_VAR_R); if (EG(exception)) { + ZVAL_NULL(result); FREE_OP1(); FREE_OP2(); FREE_OP_DATA(); @@ -9715,8 +9721,11 @@ ZEND_VM_HANDLER(207, ZEND_FRAMELESS_ICALL_3, ANY, ANY, SPEC(OBSERVER)) } else #endif { + zval tmp_result; + ZVAL_NULL(&tmp_result); zend_frameless_function_3 function = (zend_frameless_function_3)ZEND_FLF_HANDLER(opline); - function(result, arg1, arg2, arg3); + function(&tmp_result, arg1, arg2, arg3); + ZVAL_COPY_VALUE(result, &tmp_result); } FREE_OP1(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 6cb6ff41ec8d9..a9bd2bbbf3874 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3738,10 +3738,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_2_SPEC_HANDLER SAVE_OPLINE(); zval *result = EX_VAR(opline->result.var); - ZVAL_NULL(result); zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R); zval *arg2 = get_zval_ptr_deref(opline->op2_type, opline->op2, BP_VAR_R); if (EG(exception)) { + ZVAL_NULL(result); FREE_OP(opline->op1_type, opline->op1.var); FREE_OP(opline->op2_type, opline->op2.var); HANDLE_EXCEPTION(); @@ -3753,8 +3753,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_2_SPEC_HANDLER } else #endif { + zval tmp_result; + ZVAL_NULL(&tmp_result); zend_frameless_function_2 function = (zend_frameless_function_2)ZEND_FLF_HANDLER(opline); - function(result, arg1, arg2); + function(&tmp_result, arg1, arg2); + ZVAL_COPY_VALUE(result, &tmp_result); } FREE_OP(opline->op1_type, opline->op1.var); @@ -3772,10 +3775,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_2_SPEC_OBSERVE SAVE_OPLINE(); zval *result = EX_VAR(opline->result.var); - ZVAL_NULL(result); zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R); zval *arg2 = get_zval_ptr_deref(opline->op2_type, opline->op2, BP_VAR_R); if (EG(exception)) { + ZVAL_NULL(result); FREE_OP(opline->op1_type, opline->op1.var); FREE_OP(opline->op2_type, opline->op2.var); HANDLE_EXCEPTION(); @@ -3787,8 +3790,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_2_SPEC_OBSERVE } else #endif { + zval tmp_result; + ZVAL_NULL(&tmp_result); zend_frameless_function_2 function = (zend_frameless_function_2)ZEND_FLF_HANDLER(opline); - function(result, arg1, arg2); + function(&tmp_result, arg1, arg2); + ZVAL_COPY_VALUE(result, &tmp_result); } FREE_OP(opline->op1_type, opline->op1.var); @@ -3806,11 +3812,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_3_SPEC_HANDLER SAVE_OPLINE(); zval *result = EX_VAR(opline->result.var); - ZVAL_NULL(result); zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R); zval *arg2 = get_zval_ptr_deref(opline->op2_type, opline->op2, BP_VAR_R); zval *arg3 = get_op_data_zval_ptr_deref_r((opline+1)->op1_type, (opline+1)->op1); if (EG(exception)) { + ZVAL_NULL(result); FREE_OP(opline->op1_type, opline->op1.var); FREE_OP(opline->op2_type, opline->op2.var); FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); @@ -3823,8 +3829,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_3_SPEC_HANDLER } else #endif { + zval tmp_result; + ZVAL_NULL(&tmp_result); zend_frameless_function_3 function = (zend_frameless_function_3)ZEND_FLF_HANDLER(opline); - function(result, arg1, arg2, arg3); + function(&tmp_result, arg1, arg2, arg3); + ZVAL_COPY_VALUE(result, &tmp_result); } FREE_OP(opline->op1_type, opline->op1.var); @@ -3846,11 +3855,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_3_SPEC_OBSERVE SAVE_OPLINE(); zval *result = EX_VAR(opline->result.var); - ZVAL_NULL(result); zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R); zval *arg2 = get_zval_ptr_deref(opline->op2_type, opline->op2, BP_VAR_R); zval *arg3 = get_op_data_zval_ptr_deref_r((opline+1)->op1_type, (opline+1)->op1); if (EG(exception)) { + ZVAL_NULL(result); FREE_OP(opline->op1_type, opline->op1.var); FREE_OP(opline->op2_type, opline->op2.var); FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); @@ -3863,8 +3872,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_3_SPEC_OBSERVE } else #endif { + zval tmp_result; + ZVAL_NULL(&tmp_result); zend_frameless_function_3 function = (zend_frameless_function_3)ZEND_FLF_HANDLER(opline); - function(result, arg1, arg2, arg3); + function(&tmp_result, arg1, arg2, arg3); + ZVAL_COPY_VALUE(result, &tmp_result); } FREE_OP(opline->op1_type, opline->op1.var); @@ -4275,9 +4287,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED_ SAVE_OPLINE(); zval *result = EX_VAR(opline->result.var); - ZVAL_NULL(result); zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R); if (EG(exception)) { + ZVAL_NULL(result); FREE_OP(opline->op1_type, opline->op1.var); HANDLE_EXCEPTION(); } @@ -4288,8 +4300,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED_ } else #endif { + zval tmp_result; + ZVAL_NULL(&tmp_result); zend_frameless_function_1 function = (zend_frameless_function_1)ZEND_FLF_HANDLER(opline); - function(result, arg1); + function(&tmp_result, arg1); + ZVAL_COPY_VALUE(result, &tmp_result); } FREE_OP(opline->op1_type, opline->op1.var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -4301,9 +4316,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_1_SPEC_OBSERVE SAVE_OPLINE(); zval *result = EX_VAR(opline->result.var); - ZVAL_NULL(result); zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R); if (EG(exception)) { + ZVAL_NULL(result); FREE_OP(opline->op1_type, opline->op1.var); HANDLE_EXCEPTION(); } @@ -4314,8 +4329,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_1_SPEC_OBSERVE } else #endif { + zval tmp_result; + ZVAL_NULL(&tmp_result); zend_frameless_function_1 function = (zend_frameless_function_1)ZEND_FLF_HANDLER(opline); - function(result, arg1); + function(&tmp_result, arg1); + ZVAL_COPY_VALUE(result, &tmp_result); } FREE_OP(opline->op1_type, opline->op1.var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 34d383c7f5f7c..54fe7b3818ba4 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -17103,20 +17103,33 @@ static void jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint3 zend_jit_addr op1_addr = OP1_ADDR(); ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr); ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr); - jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL); + ir_ref tmp_result_ref = IR_UNUSED, result_ref; if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) { zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1); } if (op1_info & MAY_BE_REF) { op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref); } + if (op1_addr == res_addr) { + tmp_result_ref = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval))); + jit_set_Z_TYPE_INFO(jit, ZEND_ADDR_REF_ZVAL(tmp_result_ref), IS_NULL); + result_ref = tmp_result_ref; + } else { + jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL); + result_ref = res_ref; + } ir_ref skip_observer = IR_UNUSED; if (ZEND_OBSERVER_ENABLED) { skip_observer = jit_frameless_observer(jit, opline); } - ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref); + ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), result_ref, op1_ref); + + if (op1_addr == res_addr) { + jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, ZEND_ADDR_REF_ZVAL(tmp_result_ref), MAY_BE_ANY, 0); + ir_AFREE(ir_CONST_ADDR(sizeof(zval))); + } if (skip_observer != IR_UNUSED) { ir_MERGE_WITH(skip_observer); @@ -17145,7 +17158,7 @@ static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint3 ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr); ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr); ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr); - jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL); + ir_ref tmp_result_ref = IR_UNUSED, result_ref; if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) { zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1); } @@ -17158,13 +17171,26 @@ static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint3 if (op2_info & MAY_BE_REF) { op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref); } + if (op1_addr == res_addr || op2_addr == res_addr) { + tmp_result_ref = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval))); + jit_set_Z_TYPE_INFO(jit, ZEND_ADDR_REF_ZVAL(tmp_result_ref), IS_NULL); + result_ref = tmp_result_ref; + } else { + jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL); + result_ref = res_ref; + } ir_ref skip_observer = IR_UNUSED; if (ZEND_OBSERVER_ENABLED) { skip_observer = jit_frameless_observer(jit, opline); } - ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref); + ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), result_ref, op1_ref, op2_ref); + + if (op1_addr == res_addr || op2_addr == res_addr) { + jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, ZEND_ADDR_REF_ZVAL(tmp_result_ref), MAY_BE_ANY, 0); + ir_AFREE(ir_CONST_ADDR(sizeof(zval))); + } if (skip_observer != IR_UNUSED) { ir_MERGE_WITH(skip_observer); @@ -17204,7 +17230,7 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint3 ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr); ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr); ir_ref op3_ref = jit_ZVAL_ADDR(jit, op3_addr); - jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL); + ir_ref tmp_result_ref = IR_UNUSED, result_ref; if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) { zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1); } @@ -17223,13 +17249,26 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint3 if (op1_data_info & MAY_BE_REF) { op3_ref = jit_ZVAL_DEREF_ref(jit, op3_ref); } + if (op1_addr == res_addr || op2_addr == res_addr || op3_addr == res_addr) { + tmp_result_ref = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval))); + jit_set_Z_TYPE_INFO(jit, ZEND_ADDR_REF_ZVAL(tmp_result_ref), IS_NULL); + result_ref = tmp_result_ref; + } else { + jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL); + result_ref = res_ref; + } ir_ref skip_observer = IR_UNUSED; if (ZEND_OBSERVER_ENABLED) { skip_observer = jit_frameless_observer(jit, opline); } - ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref); + ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), result_ref, op1_ref, op2_ref, op3_ref); + + if (op1_addr == res_addr || op2_addr == res_addr || op3_addr == res_addr) { + jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, ZEND_ADDR_REF_ZVAL(tmp_result_ref), MAY_BE_ANY, 0); + ir_AFREE(ir_CONST_ADDR(sizeof(zval))); + } if (skip_observer != IR_UNUSED) { ir_MERGE_WITH(skip_observer); diff --git a/ext/standard/tests/array/gh14873.phpt b/ext/standard/tests/array/gh14873.phpt new file mode 100644 index 0000000000000..f1680efd5a3f2 --- /dev/null +++ b/ext/standard/tests/array/gh14873.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-14873 (PHP 8.4 min function fails on typed integer) +--FILE-- + +--EXPECT-- +string(3) "boo" +int(5) +int(5)