diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index 6ebd85c5f1b..8b25bb80460 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -230,6 +230,8 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_H void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D); bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D); +void ZEND_FASTCALL zend_jit_undefined_long_key(EXECUTE_DATA_D); +void ZEND_FASTCALL zend_jit_undefined_string_key(EXECUTE_DATA_D); zend_constant* ZEND_FASTCALL zend_jit_get_constant(const zval *key, uint32_t flags); zend_constant* ZEND_FASTCALL zend_jit_check_constant(const zval *key); diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index f1ecd7a580a..0e4faa08b58 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -2429,92 +2429,22 @@ static int zend_jit_trace_exit_stub(zend_jit_ctx *jit) static int zend_jit_undefined_offset_stub(zend_jit_ctx *jit) { - ir_ref opline = ir_LOAD_A(jit_EX(opline)); - ir_ref ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var))); - ir_ref if_const, end1, ref1; - - if (sizeof(void*) == 8) { - ref = ir_ZEXT_A(ref); + if (GCC_GLOBAL_REGS) { + ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key)); + } else { + ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key), jit_FP(jit)); } - jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(jit_FP(jit), ref), ir_CONST_U32(IS_NULL)); - - if_const = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(opline, offsetof(zend_op, op2_type))), ir_CONST_U8(IS_CONST))); - - ir_IF_TRUE(if_const); -#if ZEND_USE_ABS_CONST_ADDR - ref1 = ir_LOAD_A(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.zv))); -#else - ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.constant))); - if (sizeof(void*) == 8) { - ref = ir_SEXT_A(ref); - } - ref1 = ir_ADD_A(ref, opline); -#endif - - end1 = ir_END(); - - ir_IF_FALSE(if_const); - ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.var))); - if (sizeof(void*) == 8) { - ref = ir_ZEXT_A(ref); - } - ref = ir_ADD_A(jit_FP(jit), ref); - - ir_MERGE_WITH(end1); - ref = ir_PHI_2(IR_ADDR, ref, ref1); - - ref = jit_Z_LVAL_ref(jit, ref); - ir_CALL_3(IR_VOID, ir_CONST_FUNC(zend_error), - ir_CONST_U8(E_WARNING), - ir_CONST_ADDR("Undefined array key " ZEND_LONG_FMT), - ref); - ir_RETURN(IR_VOID); return 1; } static int zend_jit_undefined_key_stub(zend_jit_ctx *jit) { - ir_ref opline = ir_LOAD_A(jit_EX(opline)); - ir_ref ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var))); - ir_ref if_const, end1, ref1; - - if (sizeof(void*) == 8) { - ref = ir_ZEXT_A(ref); + if (GCC_GLOBAL_REGS) { + ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key)); + } else { + ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key), jit_FP(jit)); } - jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(jit_FP(jit), ref), ir_CONST_U32(IS_NULL)); - - if_const = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(opline, offsetof(zend_op, op2_type))), ir_CONST_U8(IS_CONST))); - - ir_IF_TRUE(if_const); -#if ZEND_USE_ABS_CONST_ADDR - ref1 = ir_LOAD_A(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.zv))); -#else - ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.constant))); - if (sizeof(void*) == 8) { - ref = ir_SEXT_A(ref); - } - ref1 = ir_ADD_A(ref, opline); -#endif - - end1 = ir_END(); - - ir_IF_FALSE(if_const); - ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.var))); - if (sizeof(void*) == 8) { - ref = ir_ZEXT_A(ref); - } - ref = ir_ADD_A(jit_FP(jit), ref); - - ir_MERGE_WITH(end1); - ref = ir_PHI_2(IR_ADDR, ref, ref1); - - ref = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_string, val)); - ir_CALL_3(IR_VOID, ir_CONST_FUNC(zend_error), - ir_CONST_U8(E_WARNING), - ir_CONST_ADDR("Undefined array key \"%s\""), - ref); - ir_RETURN(IR_VOID); return 1; } @@ -3039,6 +2969,8 @@ static void zend_jit_setup_disasm(void) REGISTER_HELPER(zend_jit_free_trampoline_helper); REGISTER_HELPER(zend_jit_verify_return_slow); REGISTER_HELPER(zend_jit_deprecated_helper); + REGISTER_HELPER(zend_jit_undefined_long_key); + REGISTER_HELPER(zend_jit_undefined_string_key); REGISTER_HELPER(zend_jit_copy_extra_args_helper); REGISTER_HELPER(zend_jit_vm_stack_free_args_helper); REGISTER_HELPER(zend_free_extra_named_params); diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index 3a530de1ba6..c12b141d3eb 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -194,6 +194,43 @@ bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D) return 1; } +void ZEND_FASTCALL zend_jit_undefined_long_key(EXECUTE_DATA_D) +{ + const zend_op *opline = EX(opline); + zval *result = EX_VAR(opline->result.var); + zval *dim; + + ZVAL_NULL(result); + if (opline->op2_type == IS_CONST) { + dim = RT_CONSTANT(opline, opline->op2); + } else { + dim = EX_VAR(opline->op2.var); + } + ZEND_ASSERT(Z_TYPE_P(dim) == IS_LONG); + zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, Z_LVAL_P(dim)); +} + +void ZEND_FASTCALL zend_jit_undefined_string_key(EXECUTE_DATA_D) +{ + const zend_op *opline = EX(opline); + zval *result = EX_VAR(opline->result.var); + zval *dim; + zend_ulong lval; + + ZVAL_NULL(result); + if (opline->op2_type == IS_CONST) { + dim = RT_CONSTANT(opline, opline->op2); + } else { + dim = EX_VAR(opline->op2.var); + } + ZEND_ASSERT(Z_TYPE_P(dim) == IS_STRING); + if (ZEND_HANDLE_NUMERIC(Z_STR_P(dim), lval)) { + zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, lval); + } else { + zend_error(E_WARNING, "Undefined array key \"%s\"", Z_STRVAL_P(dim)); + } +} + ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_profile_helper(ZEND_OPCODE_HANDLER_ARGS) { zend_op_array *op_array = (zend_op_array*)EX(func); diff --git a/ext/opcache/tests/jit/gh12812.phpt b/ext/opcache/tests/jit/gh12812.phpt new file mode 100644 index 00000000000..267abf2aae0 --- /dev/null +++ b/ext/opcache/tests/jit/gh12812.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-12812: JIT: Integer string in variable used as offset produces wrong undefined array key warning +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- +getMessage(), "\n"; +} +try { + var_dump($container[$dimension]); +} catch (\Throwable $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +Warning: Undefined array key 7 in %s on line %d +NULL + +Warning: Undefined array key 7 in %s on line %d +NULL