Accurate use of proxy_call

This commit is contained in:
Dmitry Stogov 2015-04-09 21:42:23 +03:00
parent 5d62837d5b
commit 529bf737ca
7 changed files with 23 additions and 135 deletions

View File

@ -3070,16 +3070,7 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca
get_function_via_handler:
if (fcc->object && fcc->calling_scope == ce_org) {
if (strict_class && ce_org->__call) {
fcc->function_handler = emalloc(sizeof(zend_internal_function));
fcc->function_handler->internal_function.type = ZEND_INTERNAL_FUNCTION;
fcc->function_handler->internal_function.module = (ce_org->type == ZEND_INTERNAL_CLASS) ? ce_org->info.internal.module : NULL;
fcc->function_handler->internal_function.handler = zend_std_call_user_call;
fcc->function_handler->internal_function.arg_info = NULL;
fcc->function_handler->internal_function.num_args = 0;
fcc->function_handler->internal_function.scope = ce_org;
fcc->function_handler->internal_function.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
fcc->function_handler->internal_function.function_name = mname;
zend_string_addref(mname);
fcc->function_handler = zend_get_proxy_call_func(ce_org, mname, 0);
call_via_handler = 1;
retval = 1;
} else if (fcc->object->handlers->get_method) {
@ -3092,7 +3083,7 @@ get_function_via_handler:
if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
zend_string_release(fcc->function_handler->common.function_name);
}
efree(fcc->function_handler);
zend_free_proxy_call_func(fcc->function_handler);
}
} else {
retval = 1;
@ -3250,14 +3241,13 @@ again:
ret = zend_is_callable_check_func(check_flags, callable, fcc, 0, error);
if (fcc == &fcc_local &&
fcc->function_handler &&
((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION &&
(fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) ||
fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
zend_string_release(fcc->function_handler->common.function_name);
}
efree(fcc->function_handler);
zend_free_proxy_call_func(fcc->function_handler);
}
return ret;
@ -3338,14 +3328,13 @@ again:
ret = zend_is_callable_check_func(check_flags, method, fcc, strict_class, error);
if (fcc == &fcc_local &&
fcc->function_handler &&
((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION &&
(fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) ||
fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
zend_string_release(fcc->function_handler->common.function_name);
}
efree(fcc->function_handler);
zend_free_proxy_call_func(fcc->function_handler);
}
return ret;
@ -3414,14 +3403,13 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam
add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name));
}
if (fcc.function_handler &&
((fcc.function_handler->type == ZEND_INTERNAL_FUNCTION &&
(fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
((fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) ||
fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
if (fcc.function_handler->type != ZEND_OVERLOADED_FUNCTION) {
zend_string_release(fcc.function_handler->common.function_name);
}
efree(fcc.function_handler);
zend_free_proxy_call_func(fcc.function_handler);
}
return 1;
}

View File

@ -2506,8 +2506,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
if (prev_call &&
prev_call->func &&
!ZEND_USER_CODE(prev_call->func->common.type) &&
!(prev_call->func->common.type == ZEND_INTERNAL_FUNCTION &&
(prev_call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER))) {
!(prev_call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) {
break;
}
if (prev->func && ZEND_USER_CODE(prev->func->common.type)) {

View File

@ -915,47 +915,6 @@ static void zend_std_unset_dimension(zval *object, zval *offset) /* {{{ */
}
/* }}} */
ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
{
zend_internal_function *func = (zend_internal_function *)EX(func);
zval method_name, method_args;
zval method_result;
zend_class_entry *ce = Z_OBJCE_P(getThis());
array_init_size(&method_args, ZEND_NUM_ARGS());
if (UNEXPECTED(zend_copy_parameters_array(ZEND_NUM_ARGS(), &method_args) == FAILURE)) {
zval_dtor(&method_args);
zend_error(E_EXCEPTION | E_ERROR, "Cannot get arguments for __call");
RETURN_FALSE;
}
ZVAL_STR(&method_name, func->function_name); /* no dup - it's a copy */
/* __call handler is called with two arguments:
method name
array of method parameters
*/
zend_call_method_with_2_params(getThis(), ce, &ce->__call, ZEND_CALL_FUNC_NAME, &method_result, &method_name, &method_args);
if (Z_TYPE(method_result) != IS_UNDEF) {
RETVAL_ZVAL_FAST(&method_result);
zval_ptr_dtor(&method_result);
}
/* now destruct all auxiliaries */
zval_ptr_dtor(&method_args);
zval_ptr_dtor(&method_name);
/* destruct the function also, then - we have allocated it in get_method */
efree_size(func, sizeof(zend_internal_function));
#if ZEND_DEBUG
execute_data->func = NULL;
#endif
}
/* }}} */
/* Ensures that we're allowed to call a private method.
* Returns the function address that should be called, or NULL
* if no such function exists.
@ -1034,12 +993,6 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope)
}
/* }}} */
static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
{
return (union _zend_function *)zend_get_proxy_call_func(ce, method_name, 0);
}
/* }}} */
static union _zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key) /* {{{ */
{
zend_object *zobj = *obj_ptr;
@ -1063,7 +1016,7 @@ static union _zend_function *zend_std_get_method(zend_object **obj_ptr, zend_str
STR_ALLOCA_FREE(lc_method_name, use_heap);
}
if (zobj->ce->__call) {
return zend_get_user_call_function(zobj->ce, method_name);
return zend_get_proxy_call_func(zobj->ce, method_name, 0);
} else {
return NULL;
}
@ -1082,7 +1035,7 @@ static union _zend_function *zend_std_get_method(zend_object **obj_ptr, zend_str
fbc = updated_fbc;
} else {
if (zobj->ce->__call) {
fbc = zend_get_user_call_function(zobj->ce, method_name);
fbc = zend_get_proxy_call_func(zobj->ce, method_name, 0);
} else {
zend_error(E_EXCEPTION | E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name->val, EG(scope) ? EG(scope)->name->val : "");
fbc = NULL;
@ -1109,7 +1062,7 @@ static union _zend_function *zend_std_get_method(zend_object **obj_ptr, zend_str
*/
if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc), EG(scope)))) {
if (zobj->ce->__call) {
fbc = zend_get_user_call_function(zobj->ce, method_name);
fbc = zend_get_proxy_call_func(zobj->ce, method_name, 0);
} else {
zend_error(E_EXCEPTION | E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name->val, EG(scope) ? EG(scope)->name->val : "");
fbc = NULL;
@ -1125,54 +1078,6 @@ static union _zend_function *zend_std_get_method(zend_object **obj_ptr, zend_str
}
/* }}} */
ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
{
zend_internal_function *func = (zend_internal_function *)EX(func);
zval method_name, method_args;
zval method_result;
zend_class_entry *ce = EG(scope);
array_init_size(&method_args, ZEND_NUM_ARGS());
if (UNEXPECTED(zend_copy_parameters_array(ZEND_NUM_ARGS(), &method_args) == FAILURE)) {
zval_dtor(&method_args);
zend_error(E_EXCEPTION | E_ERROR, "Cannot get arguments for " ZEND_CALLSTATIC_FUNC_NAME);
RETURN_FALSE;
}
ZVAL_STR(&method_name, func->function_name); /* no dup - it's a copy */
/* __callStatic handler is called with two arguments:
method name
array of method parameters
*/
zend_call_method_with_2_params(NULL, ce, &ce->__callstatic, ZEND_CALLSTATIC_FUNC_NAME, &method_result, &method_name, &method_args);
if (Z_TYPE(method_result) != IS_UNDEF) {
RETVAL_ZVAL_FAST(&method_result);
zval_ptr_dtor(&method_result);
}
/* now destruct all auxiliaries */
zval_ptr_dtor(&method_args);
zval_ptr_dtor(&method_name);
/* destruct the function also, then - we have allocated it in get_method */
efree_size(func, sizeof(zend_internal_function));
#if ZEND_DEBUG
execute_data->func = NULL;
#endif
}
/* }}} */
static inline union _zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
{
return (union _zend_function *)zend_get_proxy_call_func(ce, method_name, 1);
}
/* }}} */
/* This is not (yet?) in the API, but it belongs in the built-in objects callbacks */
ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_string *function_name, const zval *key) /* {{{ */
{
zend_function *fbc = NULL;
@ -1207,9 +1112,9 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st
if (ce->__call &&
Z_OBJ(EG(current_execute_data)->This) &&
instanceof_function(Z_OBJCE(EG(current_execute_data)->This), ce)) {
return zend_get_user_call_function(ce, function_name);
return zend_get_proxy_call_func(ce, function_name, 0);
} else if (ce->__callstatic) {
return zend_get_user_callstatic_function(ce, function_name);
return zend_get_proxy_call_func(ce, function_name, 1);
} else {
return NULL;
}
@ -1235,7 +1140,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st
fbc = updated_fbc;
} else {
if (ce->__callstatic) {
fbc = zend_get_user_callstatic_function(ce, function_name);
fbc = zend_get_proxy_call_func(ce, function_name, 1);
} else {
zend_error(E_EXCEPTION | E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name->val, EG(scope) ? EG(scope)->name->val : "");
fbc = NULL;
@ -1246,7 +1151,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st
*/
if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc), EG(scope)))) {
if (ce->__callstatic) {
fbc = zend_get_user_callstatic_function(ce, function_name);
fbc = zend_get_proxy_call_func(ce, function_name, 1);
} else {
zend_error(E_EXCEPTION | E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name->val, EG(scope) ? EG(scope)->name->val : "");
fbc = NULL;

View File

@ -179,7 +179,6 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope)
ZEND_API int zend_check_property_access(zend_object *zobj, zend_string *prop_info_name);
ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS);
END_EXTERN_C()
#endif

View File

@ -242,7 +242,7 @@ ZEND_API void zend_init_proxy_call_func(zend_op_array *func, zend_op *opline)
func->opcodes = opline;
}
ZEND_API zend_op_array *zend_get_proxy_call_func(zend_class_entry *ce, zend_string *method_name, int is_static)
ZEND_API zend_function *zend_get_proxy_call_func(zend_class_entry *ce, zend_string *method_name, int is_static)
{
zend_op_array *func;
zend_function *fbc = is_static? ce->__callstatic : ce->__call;
@ -273,7 +273,7 @@ ZEND_API zend_op_array *zend_get_proxy_call_func(zend_class_entry *ce, zend_stri
func->function_name = zend_string_copy(method_name);
}
return func;
return (zend_function*)func;
}
/*

View File

@ -73,7 +73,7 @@ ZEND_API zend_object_handlers *zend_get_std_object_handlers(void);
ZEND_API void zend_init_proxy_call_func(zend_op_array *func, zend_op *opline);
ZEND_API zend_op_array *zend_get_proxy_call_func(zend_class_entry *ce, zend_string *method_name, int is_static);
ZEND_API zend_function *zend_get_proxy_call_func(zend_class_entry *ce, zend_string *method_name, int is_static);
END_EXTERN_C()

View File

@ -265,7 +265,6 @@ static void _default_lookup_entry(zval *object, char *name, int name_len, zval *
static zend_function *_copy_function(zend_function *fptr) /* {{{ */
{
if (fptr
&& fptr->type == ZEND_INTERNAL_FUNCTION
&& (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0)
{
zend_function *copy_fptr;
@ -283,11 +282,10 @@ static zend_function *_copy_function(zend_function *fptr) /* {{{ */
static void _free_function(zend_function *fptr) /* {{{ */
{
if (fptr
&& fptr->type == ZEND_INTERNAL_FUNCTION
&& (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0)
{
zend_string_release(fptr->internal_function.function_name);
efree(fptr);
zend_free_proxy_call_func(fptr);
}
}
/* }}} */
@ -2280,7 +2278,7 @@ ZEND_METHOD(reflection_parameter, __construct)
if (fptr->type != ZEND_OVERLOADED_FUNCTION) {
zend_string_release(fptr->common.function_name);
}
efree(fptr);
zend_free_proxy_call_func(fptr);
}
if (is_closure) {
zval_ptr_dtor(reference);
@ -2841,7 +2839,7 @@ ZEND_METHOD(reflection_method, getClosure)
}
/* This is an original closure object and __invoke is to be called. */
if (Z_OBJCE_P(obj) == zend_ce_closure && mptr->type == ZEND_INTERNAL_FUNCTION &&
if (Z_OBJCE_P(obj) == zend_ce_closure &&
(mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0)
{
RETURN_ZVAL(obj, 1, 0);
@ -3043,8 +3041,7 @@ ZEND_METHOD(reflection_method, invokeArgs)
/*
* Copy the zend_function when calling via handler (e.g. Closure::__invoke())
*/
if (mptr->type == ZEND_INTERNAL_FUNCTION &&
(mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0) {
if ((mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0) {
fcc.function_handler = _copy_function(mptr);
}