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).
This commit is contained in:
Nikita Popov 2019-09-05 10:27:19 +02:00
parent 8522cdd6fa
commit ee4b11c668
8 changed files with 71 additions and 93 deletions

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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