From: Nikita Popov Date: Thu, 5 Sep 2019 08:27:19 +0000 (+0200) Subject: Detect calls to abstract methods in get_method() already X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ee4b11c66885dee5d17dbe11daf262cd953d33da;p=php Detect calls to abstract methods in get_method() already Instead of checking for this during DO_FCALL, already detect this case during get_method()/get_static_method(), similar to visibility checks. This causes a minor difference in behavior, in that arguments will no longer be evaluated. I think this is correct though (and consistent with visibility errors). --- diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index eec9f6a479..570d5886bd 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1553,12 +1553,6 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(c ZSTR_VAL(fbc->common.function_name)); } -static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_abstract_method(const zend_function *fbc) -{ - zend_throw_error(NULL, "Cannot call abstract method %s::%s()", - ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name)); -} - static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value OPLINE_DC EXECUTE_DATA_DC) { zend_uchar c; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 5621471179..3f2dd8a241 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1234,6 +1234,13 @@ static ZEND_COLD zend_never_inline void zend_bad_method_call(zend_function *fbc, } /* }}} */ +static ZEND_COLD zend_never_inline void zend_abstract_method_call(zend_function *fbc) /* {{{ */ +{ + zend_throw_error(NULL, "Cannot call abstract method %s::%s()", + ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name)); +} +/* }}} */ + ZEND_API zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key) /* {{{ */ { zend_object *zobj = *obj_ptr; @@ -1294,6 +1301,10 @@ ZEND_API zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string * } exit: + if (fbc && UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_ABSTRACT)) { + zend_abstract_method_call(fbc); + fbc = NULL; + } if (UNEXPECTED(!key)) { ZSTR_ALLOCA_FREE(lc_method_name, use_heap); } @@ -1379,6 +1390,11 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st } } + if (fbc && UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_ABSTRACT)) { + zend_abstract_method_call(fbc); + fbc = NULL; + } + if (UNEXPECTED(!key)) { zend_string_release_ex(lc_function_name, 0); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f488f803f0..acca3caf4c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4154,27 +4154,9 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) zend_execute_data *call = EX(call); zend_function *fbc = call->func; zval *ret; - zval retval; SAVE_OPLINE(); EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - zend_abstract_method(fbc); -ZEND_VM_C_LABEL(fcall_except): - UNDEF_RESULT(); - if (!RETURN_VALUE_USED(opline)) { - ret = &retval; - ZVAL_UNDEF(ret); - } - ZEND_VM_C_GOTO(fcall_end); - } else { - zend_deprecated_function(fbc); - if (UNEXPECTED(EG(exception) != NULL)) { - ZEND_VM_C_GOTO(fcall_except); - } - } - } if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { ret = NULL; @@ -4197,7 +4179,21 @@ ZEND_VM_C_LABEL(fcall_except): zend_execute_ex(call); } } else { + zval retval; ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); + + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { + zend_deprecated_function(fbc); + if (UNEXPECTED(EG(exception) != NULL)) { + UNDEF_RESULT(); + if (!RETURN_VALUE_USED(opline)) { + ret = &retval; + ZVAL_UNDEF(ret); + } + ZEND_VM_C_GOTO(fcall_end); + } + } + call->prev_execute_data = execute_data; EG(current_execute_data) = call; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 1c2c6ab7a3..ca877d4878 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1572,27 +1572,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV zend_execute_data *call = EX(call); zend_function *fbc = call->func; zval *ret; - zval retval; SAVE_OPLINE(); EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - zend_abstract_method(fbc); -fcall_except: - UNDEF_RESULT(); - if (!0) { - ret = &retval; - ZVAL_UNDEF(ret); - } - goto fcall_end; - } else { - zend_deprecated_function(fbc); - if (UNEXPECTED(EG(exception) != NULL)) { - goto fcall_except; - } - } - } if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { ret = NULL; @@ -1615,7 +1597,21 @@ fcall_except: zend_execute_ex(call); } } else { + zval retval; ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); + + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { + zend_deprecated_function(fbc); + if (UNEXPECTED(EG(exception) != NULL)) { + UNDEF_RESULT(); + if (!0) { + ret = &retval; + ZVAL_UNDEF(ret); + } + goto fcall_end; + } + } + call->prev_execute_data = execute_data; EG(current_execute_data) = call; @@ -1677,27 +1673,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV zend_execute_data *call = EX(call); zend_function *fbc = call->func; zval *ret; - zval retval; SAVE_OPLINE(); EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - zend_abstract_method(fbc); -fcall_except: - UNDEF_RESULT(); - if (!1) { - ret = &retval; - ZVAL_UNDEF(ret); - } - goto fcall_end; - } else { - zend_deprecated_function(fbc); - if (UNEXPECTED(EG(exception) != NULL)) { - goto fcall_except; - } - } - } if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { ret = NULL; @@ -1720,7 +1698,21 @@ fcall_except: zend_execute_ex(call); } } else { + zval retval; ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); + + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { + zend_deprecated_function(fbc); + if (UNEXPECTED(EG(exception) != NULL)) { + UNDEF_RESULT(); + if (!1) { + ret = &retval; + ZVAL_UNDEF(ret); + } + goto fcall_end; + } + } + call->prev_execute_data = execute_data; EG(current_execute_data) = call; diff --git a/ext/opcache/jit/zend_jit_disasm_x86.c b/ext/opcache/jit/zend_jit_disasm_x86.c index 109510cdb2..6bb0c6765c 100644 --- a/ext/opcache/jit/zend_jit_disasm_x86.c +++ b/ext/opcache/jit/zend_jit_disasm_x86.c @@ -432,7 +432,7 @@ static int zend_jit_disasm_init(void) REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic); REGISTER_HELPER(zend_jit_vm_stack_free_args_helper); REGISTER_HELPER(zend_jit_copy_extra_args_helper); - REGISTER_HELPER(zend_jit_deprecated_or_abstract_helper); + REGISTER_HELPER(zend_jit_deprecated_helper); REGISTER_HELPER(zend_jit_assign_const_to_typed_ref); REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref); REGISTER_HELPER(zend_jit_assign_var_to_typed_ref); diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index bf00b1d1df..603db0ab4b 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -88,7 +88,7 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_counter_helper(ZEND_OPCODE_H ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_HANDLER_ARGS); void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D); -void ZEND_FASTCALL zend_jit_deprecated_or_abstract_helper(OPLINE_D); +void ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D); void ZEND_FASTCALL zend_jit_get_constant(const zval *key, uint32_t flags); int ZEND_FASTCALL zend_jit_check_constant(const zval *key); diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index 332488bc8b..51dbc75828 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -144,22 +144,14 @@ void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D) } } -void ZEND_FASTCALL zend_jit_deprecated_or_abstract_helper(OPLINE_D) +void ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D) { zend_execute_data *call = (zend_execute_data *) opline; zend_function *fbc = call->func; - - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - zend_throw_error(NULL, "Cannot call abstract method %s::%s()", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name)); - } else if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "", - fbc->common.scope ? "::" : "", - ZSTR_VAL(fbc->common.function_name)); - } else { - return; - } - + zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", + fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "", + fbc->common.scope ? "::" : "", + ZSTR_VAL(fbc->common.function_name)); if (EG(exception)) { #ifndef HAVE_GCC_GLOBAL_REGS zend_execute_data *execute_data = EG(current_execute_data); diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 369f91d43a..2473be4198 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -7199,31 +7199,25 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, zend_op_ar if (opline->opcode == ZEND_DO_FCALL) { if (!func) { - | test dword [r0 + offsetof(zend_op_array, fn_flags)], (ZEND_ACC_DEPRECATED|ZEND_ACC_ABSTRACT) + | test dword [r0 + offsetof(zend_op_array, fn_flags)], ZEND_ACC_DEPRECATED | jnz >1 |.cold_code |1: if (!GCC_GLOBAL_REGS) { | mov FCARG1a, RX } - | EXT_CALL zend_jit_deprecated_or_abstract_helper, r0 + | EXT_CALL zend_jit_deprecated_helper, r0 | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0 | jne ->exception_handler | mov r0, EX:RX->func // reload | jmp >1 |.code |1: - } else if (func->common.fn_flags & ZEND_ACC_ABSTRACT) { - if (!GCC_GLOBAL_REGS) { - | mov FCARG1a, RX - } - | EXT_CALL zend_jit_deprecated_or_abstract_helper, r0 - | jmp ->exception_handler } else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) { if (!GCC_GLOBAL_REGS) { | mov FCARG1a, RX } - | EXT_CALL zend_jit_deprecated_or_abstract_helper, r0 + | EXT_CALL zend_jit_deprecated_helper, r0 | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0 | jne ->exception_handler | mov r0, EX:RX->func // reload @@ -7415,31 +7409,25 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, zend_op_ar } if (opline->opcode == ZEND_DO_FCALL_BY_NAME) { if (!func) { - | test dword [r0 + offsetof(zend_op_array, fn_flags)], (ZEND_ACC_DEPRECATED|ZEND_ACC_ABSTRACT) + | test dword [r0 + offsetof(zend_op_array, fn_flags)], ZEND_ACC_DEPRECATED | jnz >1 |.cold_code |1: if (!GCC_GLOBAL_REGS) { | mov FCARG1a, RX } - | EXT_CALL zend_jit_deprecated_or_abstract_helper, r0 + | EXT_CALL zend_jit_deprecated_helper, r0 | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0 | jne ->exception_handler | mov r0, EX:RX->func // reload | jmp >1 |.code |1: - } else if (func->common.fn_flags & ZEND_ACC_ABSTRACT) { - if (!GCC_GLOBAL_REGS) { - | mov FCARG1a, RX - } - | EXT_CALL zend_jit_deprecated_or_abstract_helper, r0 - | jmp ->exception_handler } else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) { if (!GCC_GLOBAL_REGS) { | mov FCARG1a, RX } - | EXT_CALL zend_jit_deprecated_or_abstract_helper, r0 + | EXT_CALL zend_jit_deprecated_helper, r0 | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0 | jne ->exception_handler | mov r0, EX:RX->func // reload