mirror of
https://github.com/php/php-src.git
synced 2025-08-16 14:08:47 +02:00
Fixed is_callable/call_user_func mess that had done different things for very similar arguments e.g. array("A","B") and "A::B"
This commit is contained in:
parent
77baec3f6d
commit
af05ce0af6
17 changed files with 223 additions and 417 deletions
162
Zend/zend_API.c
162
Zend/zend_API.c
|
@ -2318,6 +2318,9 @@ static int zend_is_callable_check_class(char *name, int name_len, zend_fcall_inf
|
|||
} else {
|
||||
fcc->called_scope = EG(called_scope);
|
||||
fcc->calling_scope = EG(scope);
|
||||
if (!fcc->object_pp) {
|
||||
fcc->object_pp = EG(This) ? &EG(This) : NULL;
|
||||
}
|
||||
ret = 1;
|
||||
}
|
||||
} else if (name_len == sizeof("parent") - 1 &&
|
||||
|
@ -2329,6 +2332,9 @@ static int zend_is_callable_check_class(char *name, int name_len, zend_fcall_inf
|
|||
} else {
|
||||
fcc->called_scope = EG(called_scope);
|
||||
fcc->calling_scope = EG(scope)->parent;
|
||||
if (!fcc->object_pp) {
|
||||
fcc->object_pp = EG(This) ? &EG(This) : NULL;
|
||||
}
|
||||
ret = 1;
|
||||
}
|
||||
} else if (name_len == sizeof("static") - 1 &&
|
||||
|
@ -2338,10 +2344,23 @@ static int zend_is_callable_check_class(char *name, int name_len, zend_fcall_inf
|
|||
} else {
|
||||
fcc->called_scope = EG(called_scope);
|
||||
fcc->calling_scope = EG(called_scope);
|
||||
if (!fcc->object_pp) {
|
||||
fcc->object_pp = EG(This) ? &EG(This) : NULL;
|
||||
}
|
||||
ret = 1;
|
||||
}
|
||||
} else if (zend_lookup_class_ex(name, name_len, 1, &pce TSRMLS_CC) == SUCCESS) {
|
||||
fcc->called_scope = fcc->calling_scope = *pce;
|
||||
zend_class_entry *scope = EG(active_op_array) ? EG(active_op_array)->scope : NULL;
|
||||
|
||||
fcc->calling_scope = *pce;
|
||||
if (scope && !fcc->object_pp && EG(This) &&
|
||||
instanceof_function(Z_OBJCE_P(EG(This)), scope TSRMLS_CC) &&
|
||||
instanceof_function(scope, fcc->calling_scope TSRMLS_CC)) {
|
||||
fcc->object_pp = &EG(This);
|
||||
fcc->called_scope = Z_OBJCE_PP(fcc->object_pp);
|
||||
} else {
|
||||
fcc->called_scope = fcc->object_pp ? Z_OBJCE_PP(fcc->object_pp) : fcc->calling_scope;
|
||||
}
|
||||
ret = 1;
|
||||
} else {
|
||||
if (error) zend_spprintf(error, 0, "class '%.*s' not found", name_len, name);
|
||||
|
@ -2355,8 +2374,8 @@ static int zend_is_callable_check_class(char *name, int name_len, zend_fcall_inf
|
|||
static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_class_entry *ce_org = fcc->calling_scope;
|
||||
int retval;
|
||||
char *lmname, *colon;
|
||||
int retval = 0;
|
||||
char *mname, *lmname, *colon;
|
||||
int clen, mlen;
|
||||
zend_class_entry *last_scope;
|
||||
HashTable *ftable;
|
||||
|
@ -2375,9 +2394,11 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca
|
|||
Z_STRVAL_P(callable)[1] == ':'
|
||||
) {
|
||||
mlen = Z_STRLEN_P(callable) - 2;
|
||||
mname = Z_STRVAL_P(callable) + 2;
|
||||
lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + 2, mlen);
|
||||
} else {
|
||||
mlen = Z_STRLEN_P(callable);
|
||||
mname = Z_STRVAL_P(callable);
|
||||
lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), mlen);
|
||||
}
|
||||
/* Check if function with given name exists.
|
||||
|
@ -2397,7 +2418,6 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca
|
|||
colon--;
|
||||
clen = colon - Z_STRVAL_P(callable);
|
||||
mlen = Z_STRLEN_P(callable) - clen - 2;
|
||||
lmname = colon + 2;
|
||||
|
||||
if (colon == Z_STRVAL_P(callable)) {
|
||||
if (error) zend_spprintf(error, 0, "invalid function name");
|
||||
|
@ -2422,53 +2442,41 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca
|
|||
if (error) zend_spprintf(error, 0, "class '%s' is not a subclass of '%s'", ce_org->name, fcc->calling_scope->name);
|
||||
return 0;
|
||||
}
|
||||
lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + clen + 2, mlen);
|
||||
mname = Z_STRVAL_P(callable) + clen + 2;
|
||||
} else if (ce_org) {
|
||||
/* Try to fetch find static method of given class. */
|
||||
mlen = Z_STRLEN_P(callable);
|
||||
lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), Z_STRLEN_P(callable));
|
||||
mname = Z_STRVAL_P(callable);
|
||||
ftable = &ce_org->function_table;
|
||||
fcc->calling_scope = ce_org;
|
||||
} else {
|
||||
/* We already checked for plain function before. */
|
||||
if (error) zend_spprintf(error, 0, "function '%s' not found or invalid function name", Z_STRVAL_P(callable));
|
||||
if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) {
|
||||
zend_spprintf(error, 0, "function '%s' not found or invalid function name", Z_STRVAL_P(callable));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
retval = zend_hash_find(ftable, lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS ? 1 : 0;
|
||||
|
||||
if (!retval) {
|
||||
if (fcc->object_pp && fcc->calling_scope && fcc->calling_scope->__call != 0) {
|
||||
retval = 1;
|
||||
call_via_handler = 1;
|
||||
fcc->function_handler = fcc->calling_scope->__call;
|
||||
lmname = zend_str_tolower_dup(mname, mlen);
|
||||
if (zend_hash_find(ftable, lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS) {
|
||||
retval = 1;
|
||||
} else if (fcc->object_pp && Z_OBJ_HT_PP(fcc->object_pp)->get_method) {
|
||||
fcc->function_handler = Z_OBJ_HT_PP(fcc->object_pp)->get_method(fcc->object_pp, mname, mlen TSRMLS_CC);
|
||||
retval = fcc->function_handler ? 1 : 0;
|
||||
call_via_handler = 1;
|
||||
} else if (fcc->calling_scope) {
|
||||
if (fcc->calling_scope->get_static_method) {
|
||||
fcc->function_handler = fcc->calling_scope->get_static_method(fcc->calling_scope, mname, mlen TSRMLS_CC);
|
||||
} else {
|
||||
if (!fcc->object_pp && fcc->calling_scope && (fcc->calling_scope->__callstatic || fcc->calling_scope->__call)) {
|
||||
if (fcc->calling_scope->__call &&
|
||||
EG(This) &&
|
||||
Z_OBJ_HT_P(EG(This))->get_class_entry &&
|
||||
instanceof_function(Z_OBJCE_P(EG(This)), fcc->calling_scope TSRMLS_CC)) {
|
||||
retval = 1;
|
||||
call_via_handler = 1;
|
||||
fcc->function_handler = fcc->calling_scope->__call;
|
||||
fcc->object_pp = &EG(This);
|
||||
} else if (fcc->calling_scope->__callstatic) {
|
||||
retval = 1;
|
||||
call_via_handler = 1;
|
||||
fcc->function_handler = fcc->calling_scope->__callstatic;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == 0) {
|
||||
if (fcc->calling_scope) {
|
||||
if (error) zend_spprintf(error, 0, "class '%s' does not have a method '%s'", fcc->calling_scope->name, lmname);
|
||||
} else {
|
||||
if (error) zend_spprintf(error, 0, "function '%s' does not exist", lmname);
|
||||
}
|
||||
}
|
||||
fcc->function_handler = zend_std_get_static_method(fcc->calling_scope, mname, mlen TSRMLS_CC);
|
||||
}
|
||||
} else {
|
||||
if (fcc->calling_scope) {
|
||||
retval = fcc->function_handler ? 1 : 0;
|
||||
call_via_handler = 1;
|
||||
}
|
||||
efree(lmname);
|
||||
|
||||
if (retval) {
|
||||
if (fcc->calling_scope && !call_via_handler) {
|
||||
if (!fcc->object_pp && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) {
|
||||
int severity;
|
||||
char *verb;
|
||||
|
@ -2500,7 +2508,7 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca
|
|||
}
|
||||
if (retval && (check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) {
|
||||
if (fcc->function_handler->op_array.fn_flags & ZEND_ACC_PRIVATE) {
|
||||
if (!zend_check_private(fcc->function_handler, fcc->object_pp ? Z_OBJCE_PP(fcc->object_pp) : EG(scope), lmname, mlen TSRMLS_CC)) {
|
||||
if (!zend_check_private(fcc->function_handler, fcc->object_pp ? Z_OBJCE_PP(fcc->object_pp) : EG(scope), mname, mlen TSRMLS_CC)) {
|
||||
if (error) {
|
||||
if (*error) {
|
||||
efree(*error);
|
||||
|
@ -2522,20 +2530,26 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) {
|
||||
if (fcc->calling_scope) {
|
||||
if (error) zend_spprintf(error, 0, "class '%s' does not have a method '%s'", fcc->calling_scope->name, mname);
|
||||
} else {
|
||||
if (error) zend_spprintf(error, 0, "function '%s' does not exist", mname);
|
||||
}
|
||||
}
|
||||
if (fcc->object_pp) {
|
||||
fcc->called_scope = Z_OBJCE_PP(fcc->object_pp);
|
||||
}
|
||||
efree(lmname);
|
||||
if (retval && !call_via_handler) {
|
||||
if (retval) {
|
||||
fcc->initialized = 1;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */
|
||||
ZEND_API zend_bool zend_is_callable_ex(zval *callable, zval **object_pp, uint check_flags, char **callable_name, int *callable_name_len, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_bool ret;
|
||||
int callable_name_len_local;
|
||||
zend_fcall_info_cache fcc_local;
|
||||
|
||||
|
@ -2561,15 +2575,42 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
|
|||
|
||||
switch (Z_TYPE_P(callable)) {
|
||||
case IS_STRING:
|
||||
if (callable_name) {
|
||||
if (object_pp && *object_pp) {
|
||||
fcc->object_pp = object_pp;
|
||||
fcc->calling_scope = Z_OBJCE_PP(object_pp);
|
||||
if (callable_name) {
|
||||
char *ptr;
|
||||
|
||||
*callable_name_len = fcc->calling_scope->name_length + Z_STRLEN_P(callable) + sizeof("::") - 1;
|
||||
ptr = *callable_name = emalloc(*callable_name_len + 1);
|
||||
memcpy(ptr, fcc->calling_scope->name, fcc->calling_scope->name_length);
|
||||
ptr += fcc->calling_scope->name_length;
|
||||
memcpy(ptr, "::", sizeof("::") - 1);
|
||||
ptr += sizeof("::") - 1;
|
||||
memcpy(ptr, Z_STRVAL_P(callable), Z_STRLEN_P(callable) + 1);
|
||||
}
|
||||
} else if (callable_name) {
|
||||
*callable_name = estrndup(Z_STRVAL_P(callable), Z_STRLEN_P(callable));
|
||||
*callable_name_len = Z_STRLEN_P(callable);
|
||||
}
|
||||
if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
|
||||
fcc->called_scope = fcc->calling_scope;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return zend_is_callable_check_func(check_flags, callable, fcc, error TSRMLS_CC);
|
||||
ret = zend_is_callable_check_func(check_flags, callable, fcc, error TSRMLS_CC);
|
||||
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->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
|
||||
fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
|
||||
if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
|
||||
efree(fcc->function_handler->common.function_name);
|
||||
}
|
||||
efree(fcc->function_handler);
|
||||
}
|
||||
return ret;
|
||||
|
||||
case IS_ARRAY:
|
||||
{
|
||||
|
@ -2629,7 +2670,20 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
|
|||
}
|
||||
}
|
||||
|
||||
return zend_is_callable_check_func(check_flags, *method, fcc, error TSRMLS_CC);
|
||||
ret = zend_is_callable_check_func(check_flags, *method, fcc, error TSRMLS_CC);
|
||||
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->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
|
||||
fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
|
||||
if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
|
||||
efree(fcc->function_handler->common.function_name);
|
||||
}
|
||||
efree(fcc->function_handler);
|
||||
}
|
||||
return ret;
|
||||
|
||||
} else {
|
||||
if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) {
|
||||
if (!obj || (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT)) {
|
||||
|
@ -2683,7 +2737,7 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **cal
|
|||
{
|
||||
TSRMLS_FETCH();
|
||||
|
||||
return zend_is_callable_ex(callable, check_flags, callable_name, NULL, NULL, NULL TSRMLS_CC);
|
||||
return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL, NULL TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
@ -2691,13 +2745,23 @@ ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRML
|
|||
{
|
||||
zend_fcall_info_cache fcc;
|
||||
|
||||
if (zend_is_callable_ex(callable, IS_CALLABLE_STRICT, callable_name, NULL, &fcc, NULL TSRMLS_CC)) {
|
||||
if (zend_is_callable_ex(callable, NULL, IS_CALLABLE_STRICT, callable_name, NULL, &fcc, NULL TSRMLS_CC)) {
|
||||
if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) {
|
||||
zval_dtor(callable);
|
||||
array_init(callable);
|
||||
add_next_index_string(callable, fcc.calling_scope->name, 1);
|
||||
add_next_index_string(callable, fcc.function_handler->common.function_name, 1);
|
||||
}
|
||||
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->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
|
||||
fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
|
||||
if (fcc.function_handler->type != ZEND_OVERLOADED_FUNCTION) {
|
||||
efree(fcc.function_handler->common.function_name);
|
||||
}
|
||||
efree(fcc.function_handler);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -2706,7 +2770,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRML
|
|||
|
||||
ZEND_API int zend_fcall_info_init(zval *callable, uint check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, char **callable_name, char **error TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (!zend_is_callable_ex(callable, check_flags, callable_name, NULL, fcc, error TSRMLS_CC)) {
|
||||
if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, fcc, error TSRMLS_CC)) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue