From bdf7981e28a64392908e275d4d3398f8f2028162 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Sat, 26 Jul 2008 13:14:56 +0000 Subject: [PATCH] Fixed is_callable/call_user_func mess that had done different things for very similar arguments e.g. array("A","B") and "A::B" --- Zend/tests/bug32290.phpt | 4 - Zend/tests/objects_027.phpt | 2 - Zend/zend_API.c | 220 +++++++--- Zend/zend_API.h | 3 +- Zend/zend_closures.c | 63 ++- Zend/zend_compile.h | 2 + Zend/zend_execute_API.c | 385 ++---------------- Zend/zend_object_handlers.c | 13 +- Zend/zend_vm_def.h | 3 + Zend/zend_vm_execute.h | 30 ++ ext/reflection/php_reflection.c | 2 +- ext/spl/php_spl.c | 4 +- ext/spl/tests/spl_autoload_007.phpt | 6 +- .../tests/array/array_map_object1.phpt | 20 +- .../tests/array/array_map_object3.phpt | 4 +- .../tests/general_functions/bug40398.phpt | 8 - .../general_functions/callbacks_001.phpt | 4 - 17 files changed, 283 insertions(+), 490 deletions(-) diff --git a/Zend/tests/bug32290.phpt b/Zend/tests/bug32290.phpt index 169f269876..dc00ec8492 100755 --- a/Zend/tests/bug32290.phpt +++ b/Zend/tests/bug32290.phpt @@ -98,8 +98,6 @@ var_dump($x->doSomethingStatic(1)); --EXPECTF-- ===A=== TestB::doSomething(1) - -Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method TestA::doSomething() should not be called statically, assuming $this from compatible context TestB in %s on line %d TestA::doSomething(2) int(1) @@ -110,8 +108,6 @@ int(1) ===C=== TestB::doSomethingParent(1) - -Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method TestA::doSomethingParent() should not be called statically, assuming $this from compatible context TestB in %s on line %d TestA::doSomethingParent(2) int(1) diff --git a/Zend/tests/objects_027.phpt b/Zend/tests/objects_027.phpt index 1de77fb31b..b50d8446d0 100644 --- a/Zend/tests/objects_027.phpt +++ b/Zend/tests/objects_027.phpt @@ -37,8 +37,6 @@ object(foo)#%d (0) { Strict Standards: call_user_func() expects parameter 1 to be a valid callback, non-static method foo::test() should not be called statically in %s on line %d -Strict Standards: Non-static method foo::test() should not be called statically in %s on line %d - Strict Standards: Non-static method bar::show() should not be called statically in %s on line %d object(foo)#%d (0) { } diff --git a/Zend/zend_API.c b/Zend/zend_API.c index cf624cb64b..9137f3be7b 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2704,6 +2704,9 @@ static int zend_is_callable_check_class(zend_uchar utype, zstr name, int name_le } 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 (lcname_len == sizeof("parent") - 1 && @@ -2715,6 +2718,9 @@ static int zend_is_callable_check_class(zend_uchar utype, zstr name, int name_le } 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 (lcname_len == sizeof("static") - 1 && @@ -2724,10 +2730,23 @@ static int zend_is_callable_check_class(zend_uchar utype, zstr name, int name_le } 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_u_lookup_class(utype, name, name_len, &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) { @@ -2749,9 +2768,9 @@ static int zend_is_callable_check_class(zend_uchar utype, zstr name, int name_le 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; + int retval = 0; zstr lmname, mname, colon = NULL_ZSTR; - unsigned int clen = 0, mlen; + unsigned int clen = 0, lmlen, mlen; zend_class_entry *last_scope; HashTable *ftable; int call_via_handler = 0; @@ -2769,24 +2788,24 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca Z_USTRVAL_P(callable)[0] == ':' && Z_USTRVAL_P(callable)[1] == ':' ) { - zstr tmp; - - tmp.u = Z_USTRVAL_P(callable) + 2; - lmname = zend_u_str_case_fold(IS_UNICODE, tmp, Z_USTRLEN_P(callable)-2, 1, &mlen); + mlen = Z_USTRLEN_P(callable) - 2; + mname.u = Z_USTRVAL_P(callable) + 2; + lmname = zend_u_str_case_fold(IS_UNICODE, mname, mlen, 1, &lmlen); } else if (Z_TYPE_P(callable) == IS_STRING && Z_STRVAL_P(callable)[0] == ':' && Z_STRVAL_P(callable)[1] == ':' ) { - zstr tmp; - - tmp.s = Z_STRVAL_P(callable) + 2; - lmname = zend_u_str_case_fold(IS_STRING, tmp, Z_STRLEN_P(callable)-2, 1, &mlen); + mlen = Z_USTRLEN_P(callable) - 2; + mname.u = Z_USTRVAL_P(callable) + 2; + lmname = zend_u_str_case_fold(IS_STRING, mname, mlen, 1, &lmlen); } else { - lmname = zend_u_str_case_fold(Z_TYPE_P(callable), Z_UNIVAL_P(callable), Z_UNILEN_P(callable), 1, &mlen); + mlen = Z_UNILEN_P(callable); + mname = Z_UNIVAL_P(callable); + lmname = zend_u_str_case_fold(Z_TYPE_P(callable), Z_UNIVAL_P(callable), Z_UNILEN_P(callable), 1, &lmlen); } /* Check if function with given name exists. * This may be a compound name that includes namespace name */ - if (zend_u_hash_find(EG(function_table), Z_TYPE_P(callable), lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS) { + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(callable), lmname, lmlen+1, (void**)&fcc->function_handler) == SUCCESS) { efree(lmname.v); return 1; } @@ -2840,53 +2859,52 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca if (error) zend_spprintf(error, 0, "class '%v' is not a subclass of '%v'", ce_org->name, fcc->calling_scope->name); return 0; } - lmname = zend_u_str_case_fold(Z_TYPE_P(callable), mname, mlen, 1, &mlen); } else if (ce_org) { /* Try to fetch find static method of given class. */ - lmname = zend_u_str_case_fold(Z_TYPE_P(callable), Z_UNIVAL_P(callable), Z_UNILEN_P(callable), 1, &mlen); + mlen = Z_UNILEN_P(callable); + mname = Z_UNIVAL_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 '%Z' not found or invalid function name", callable); + if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) { + zend_spprintf(error, 0, "function '%Z' not found or invalid function name", callable); + } return 0; } - retval = zend_u_hash_find(ftable, Z_TYPE_P(callable), 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_u_str_case_fold(Z_TYPE_P(callable), mname, mlen, 1, &lmlen); + if (zend_u_hash_find(ftable, Z_TYPE_P(callable), lmname, lmlen+1, (void**)&fcc->function_handler) == SUCCESS) { + retval = 1; + } else if (fcc->object_pp && Z_OBJ_HT_PP(fcc->object_pp)->get_method) { + zstr method = mname; + int method_len = mlen; + + if (UG(unicode) && Z_TYPE_P(callable) == IS_STRING) { + zend_string_to_unicode(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &method.u, &method_len, mname.s, mlen TSRMLS_CC); + } else if (!UG(unicode) && Z_TYPE_P(callable) == IS_UNICODE) { + zend_unicode_to_string(ZEND_U_CONVERTER(UG(runtime_encoding_conv)), &method.s, &method_len, mname.u, mlen TSRMLS_CC); + } + fcc->function_handler = Z_OBJ_HT_PP(fcc->object_pp)->get_method(fcc->object_pp, method, method_len TSRMLS_CC); + if (method.v != mname.v) { + efree(method.v); + } + 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, Z_TYPE_P(callable), 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 '%v' does not have a method '%v'", fcc->calling_scope->name, lmname); - } else { - if (error) zend_spprintf(error, 0, "function '%v' does not exist", lmname); - } - } + fcc->function_handler = zend_std_get_static_method(fcc->calling_scope, Z_TYPE_P(callable), mname, mlen TSRMLS_CC); } - } else { - if (fcc->calling_scope) { - if (!fcc->object_pp && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) { + retval = fcc->function_handler ? 1 : 0; + call_via_handler = 1; + } + efree(lmname.v); + + 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; if (fcc->function_handler->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { @@ -2917,7 +2935,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); @@ -2939,20 +2957,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 '%v' does not have a method '%R'", fcc->calling_scope->name, Z_TYPE_P(callable), mname); + } else { + if (error) zend_spprintf(error, 0, "function '%R' does not exist", Z_TYPE_P(callable), mname); + } } if (fcc->object_pp) { fcc->called_scope = Z_OBJCE_PP(fcc->object_pp); } - efree(lmname.v); - 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, zval *callable_name, 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, zval *callable_name, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */ { + zend_bool ret; zend_fcall_info_cache fcc_local; if (callable_name) { @@ -2975,16 +2999,71 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *c switch (Z_TYPE_P(callable)) { case IS_STRING: case IS_UNICODE: - if (callable_name) { + if (object_pp && *object_pp) { + fcc->object_pp = object_pp; + fcc->calling_scope = Z_OBJCE_PP(object_pp); + if (callable_name) { + if (UG(unicode)) { + Z_TYPE_P(callable_name) = IS_UNICODE; + Z_USTRLEN_P(callable_name) = fcc->calling_scope->name_length + Z_UNILEN_P(callable) + 2; + Z_USTRVAL_P(callable_name) = eumalloc(Z_USTRLEN_P(callable_name)+1); + memcpy(Z_USTRVAL_P(callable_name), fcc->calling_scope->name.u, UBYTES(fcc->calling_scope->name_length)); + Z_USTRVAL_P(callable_name)[fcc->calling_scope->name_length] = ':'; + Z_USTRVAL_P(callable_name)[fcc->calling_scope->name_length+1] = ':'; + if (Z_TYPE_P(callable) == IS_UNICODE) { + u_memcpy(Z_USTRVAL_P(callable_name)+fcc->calling_scope->name_length+2, Z_USTRVAL_P(callable), Z_USTRLEN_P(callable)+1); + } else { + zval *method = callable; + zval copy; + int use_copy; + + zend_make_unicode_zval(method, ©, &use_copy); + u_memcpy(Z_USTRVAL_P(callable_name)+fcc->calling_scope->name_length+2, Z_USTRVAL(copy), Z_USTRLEN(copy)+1); + zval_dtor(©); + } + } else { + Z_TYPE_P(callable_name) = IS_STRING; + Z_STRLEN_P(callable_name) = fcc->calling_scope->name_length + Z_UNILEN_P(callable) + 2; + Z_STRVAL_P(callable_name) = emalloc(Z_STRLEN_P(callable_name)+1); + memcpy(Z_STRVAL_P(callable_name), fcc->calling_scope->name.s, fcc->calling_scope->name_length); + Z_STRVAL_P(callable_name)[fcc->calling_scope->name_length] = ':'; + Z_STRVAL_P(callable_name)[fcc->calling_scope->name_length+1] = ':'; + if (Z_TYPE_P(callable) == IS_STRING) { + memcpy(Z_STRVAL_P(callable_name)+fcc->calling_scope->name_length+2, Z_STRVAL_P(callable), Z_STRLEN_P(callable)+1); + } else { + zval *method = callable; + zval copy; + int use_copy; + + zend_make_string_zval(method, ©, &use_copy); + memcpy(Z_STRVAL_P(callable_name)+fcc->calling_scope->name_length+2, Z_STRVAL(copy), Z_STRLEN(copy)+1); + zval_dtor(©); + } + } + } + } else if (callable_name) { *callable_name = *callable; zval_copy_ctor(callable_name); convert_to_text(callable_name); } 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.v); + } + efree(fcc->function_handler); + } + return ret; case IS_ARRAY: { @@ -3113,7 +3192,20 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *c } } - 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.v); + } + efree(fcc->function_handler); + } + return ret; + } else { if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) { if (!obj || (Z_TYPE_PP(obj) != IS_OBJECT && Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_UNICODE)) { @@ -3171,7 +3263,7 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, zval *call { TSRMLS_FETCH(); - return zend_is_callable_ex(callable, check_flags, callable_name, NULL, NULL TSRMLS_CC); + return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL TSRMLS_CC); } /* }}} */ @@ -3179,7 +3271,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zval *callable_name TSRMLS { zend_fcall_info_cache fcc; - if (zend_is_callable_ex(callable, IS_CALLABLE_STRICT, callable_name, &fcc, NULL TSRMLS_CC)) { + if (zend_is_callable_ex(callable, NULL, IS_CALLABLE_STRICT, callable_name, &fcc, NULL TSRMLS_CC)) { if ((Z_TYPE_P(callable) == IS_STRING || Z_TYPE_P(callable) == IS_UNICODE) && fcc.calling_scope) { @@ -3189,6 +3281,16 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zval *callable_name TSRMLS add_next_index_text(callable, fcc.calling_scope->name, 1); add_next_index_text(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.v); + } + efree(fcc.function_handler); + } return 1; } return 0; @@ -3197,7 +3299,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zval *callable_name TSRMLS ZEND_API int zend_fcall_info_init(zval *callable, uint check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *callable_name, char **error TSRMLS_DC) /* {{{ */ { - if (!zend_is_callable_ex(callable, check_flags, callable_name, fcc, error TSRMLS_CC)) { + if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, fcc, error TSRMLS_CC)) { return FAILURE; } diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 1403b9fa65..df6b1198b7 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -280,10 +280,11 @@ ZEND_API void zend_wrong_param_count(TSRMLS_D); #define IS_CALLABLE_CHECK_SYNTAX_ONLY (1<<0) #define IS_CALLABLE_CHECK_NO_ACCESS (1<<1) #define IS_CALLABLE_CHECK_IS_STATIC (1<<2) +#define IS_CALLABLE_CHECK_SILENT (1<<3) #define IS_CALLABLE_STRICT (IS_CALLABLE_CHECK_IS_STATIC) -ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *callable_name, 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, zval *callable_name, zend_fcall_info_cache *fcc, char **error TSRMLS_DC); ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, zval *callable_name); ZEND_API zend_bool zend_make_callable(zval *callable, zval *callable_name TSRMLS_DC); ZEND_API const char *zend_get_module_version(const char *module_name); diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index c64557f25a..1e70319d33 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -36,7 +36,6 @@ typedef struct _zend_closure { zend_object std; zend_function func; zval *this_ptr; - zend_function *invoke; } zend_closure; static zend_class_entry *zend_ce_closure; @@ -44,6 +43,7 @@ static zend_object_handlers closure_handlers; ZEND_METHOD(Closure, __invoke) /* {{{ */ { + zend_function *func = EG(current_execute_data)->function_state.function; zval ***arguments; zval *closure_result_ptr = NULL; @@ -51,16 +51,10 @@ ZEND_METHOD(Closure, __invoke) /* {{{ */ if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), arguments) == FAILURE) { efree(arguments); zend_error(E_ERROR, "Cannot get arguments for calling closure"); - RETURN_FALSE; - } - - if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) { - efree(arguments); - RETURN_FALSE; - } - - efree(arguments); - if (closure_result_ptr) { + RETVAL_FALSE; + } else if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) { + RETVAL_FALSE; + } else if (closure_result_ptr) { if (Z_ISREF_P(closure_result_ptr) && return_value_ptr) { if (return_value) { zval_ptr_dtor(&return_value); @@ -70,13 +64,12 @@ ZEND_METHOD(Closure, __invoke) /* {{{ */ RETVAL_ZVAL(closure_result_ptr, 1, 1); } } -} -/* }}} */ + efree(arguments); -const static zend_function_entry closure_functions[] = { /* {{{ */ - ZEND_ME(Closure, __invoke, NULL, 0) - {NULL, NULL, NULL} -}; + /* destruct the function also, then - we have allocated it in get_method */ + efree(func->internal_function.function_name.v); + efree(func); +} /* }}} */ static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /* {{{ */ @@ -128,22 +121,21 @@ static zend_function *zend_closure_get_method(zval **object_ptr, zstr method_nam (ZEND_U_EQUAL(type, lc_name, lc_name_len, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1)) ) { zend_closure *closure = (zend_closure *)zend_object_store_get_object(*object_ptr TSRMLS_CC); - - if (!closure->invoke) { - closure->invoke = (zend_function*)emalloc(sizeof(zend_function)); - closure->invoke->common = closure->func.common; - closure->invoke->type = ZEND_INTERNAL_FUNCTION; - closure->invoke->internal_function.handler = ZEND_MN(Closure___invoke); - closure->invoke->internal_function.module = 0; - closure->invoke->internal_function.scope = zend_ce_closure; - if (UG(unicode)) { - closure->invoke->internal_function.function_name.u = USTR_MAKE(ZEND_INVOKE_FUNC_NAME); - } else { - closure->invoke->internal_function.function_name.s = ZEND_INVOKE_FUNC_NAME; - } + zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function)); + + invoke->common = closure->func.common; + invoke->type = ZEND_INTERNAL_FUNCTION; + invoke->internal_function.fn_flags = ZEND_ACC_CALL_VIA_HANDLER; + invoke->internal_function.handler = ZEND_MN(Closure___invoke); + invoke->internal_function.module = 0; + invoke->internal_function.scope = zend_ce_closure; + if (UG(unicode)) { + invoke->internal_function.function_name.u = USTR_MAKE(ZEND_INVOKE_FUNC_NAME); + } else { + invoke->internal_function.function_name.s = estrndup(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1); } efree(lc_name.v); - return (zend_function *)closure->invoke; + return invoke; } efree(lc_name.v); return NULL; @@ -204,13 +196,6 @@ static void zend_closure_free_storage(void *object TSRMLS_DC) /* {{{ */ zval_ptr_dtor(&closure->this_ptr); } - if (closure->invoke) { - if (UG(unicode)) { - efree(closure->invoke->internal_function.function_name.u); - } - efree(closure->invoke); - } - efree(closure); } /* }}} */ @@ -236,7 +221,7 @@ void zend_register_closure_ce(TSRMLS_D) /* {{{ */ { zend_class_entry ce; - INIT_CLASS_ENTRY(ce, "Closure", closure_functions); + INIT_CLASS_ENTRY(ce, "Closure", NULL); zend_ce_closure = zend_register_internal_class(&ce TSRMLS_CC); zend_ce_closure->ce_flags |= ZEND_ACC_FINAL_CLASS; zend_ce_closure->create_object = zend_closure_new; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index df64ee090f..e2f09ccfda 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -155,6 +155,8 @@ typedef struct _zend_try_catch_element { char *zend_visibility_string(zend_uint fn_flags); +/* function flag for internal user call handlers __call, __callstatic */ +#define ZEND_ACC_CALL_VIA_HANDLER 0x200000 typedef struct _zend_property_info { zend_uint flags; diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 6ca0e63def..0360b555b5 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -740,16 +740,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zend_class_entry *current_called_scope; zend_class_entry *calling_scope = NULL; zend_class_entry *called_scope = NULL; - zend_class_entry *check_scope_or_static = NULL; zval *current_this; zend_execute_data execute_data; - zval *method_name; - zval *params_array; - int call_via_handler = 0; char *old_func_name = NULL; - unsigned int clen, lcname_len; - int fname_len; - zstr colon, fname, cname, lcname; *fci->retval_ptr_ptr = NULL; @@ -784,304 +777,40 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } if (!fci_cache || !fci_cache->initialized) { - if (Z_TYPE_P(fci->function_name) == IS_ARRAY) { /* assume array($obj, $name) couple */ - zval **tmp_object_ptr, **tmp_real_function_name; - - if (zend_hash_index_find(Z_ARRVAL_P(fci->function_name), 0, (void **) &tmp_object_ptr) == FAILURE) { - return FAILURE; - } - if (zend_hash_index_find(Z_ARRVAL_P(fci->function_name), 1, (void **) &tmp_real_function_name) == FAILURE) { - return FAILURE; - } - fci->function_name = *tmp_real_function_name; - SEPARATE_ZVAL_IF_NOT_REF(tmp_object_ptr); - fci->object_pp = tmp_object_ptr; - Z_SET_ISREF_PP(fci->object_pp); - } - - if (fci->object_pp && !*fci->object_pp) { - fci->object_pp = NULL; - } - - if (fci->object_pp) { - if (Z_TYPE_PP(fci->object_pp) == IS_OBJECT - && (!EG(objects_store).object_buckets || !EG(objects_store).object_buckets[Z_OBJ_HANDLE_PP(fci->object_pp)].valid)) { - return FAILURE; - } - /* TBI!! new object handlers */ - if (Z_TYPE_PP(fci->object_pp) == IS_OBJECT) { - if (!IS_ZEND_STD_OBJECT(**fci->object_pp)) { - zend_error(E_WARNING, "Cannot use call_user_function on objects without a class entry"); - return FAILURE; - } - - calling_scope = called_scope = Z_OBJCE_PP(fci->object_pp); - fci->function_table = &calling_scope->function_table; - EX(object) = *fci->object_pp; - } else if (Z_TYPE_PP(fci->object_pp) == IS_STRING || - Z_TYPE_PP(fci->object_pp) == IS_UNICODE - ) { - zend_class_entry **ce; - int found = FAILURE; - - if (Z_UNILEN_PP(fci->object_pp) == sizeof("self") - 1 && - ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), "self", sizeof("self") - 1) - ) { - if (!EG(active_op_array) || !EG(active_op_array)->scope) { - zend_error(E_ERROR, "Cannot access self:: when no class scope is active"); - } - ce = &(EG(active_op_array)->scope); - found = (*ce != NULL?SUCCESS:FAILURE); - fci->object_pp = EG(This)?&EG(This):NULL; - EX(object) = EG(This); - calling_scope = *ce; - called_scope = EG(called_scope) ? EG(called_scope) : calling_scope; - } else if (EG(active_op_array) && - Z_UNILEN_PP(fci->object_pp) == sizeof("parent") - 1 && - ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), "parent", sizeof("parent") - 1) - ) { - if (!EG(active_op_array) || !EG(active_op_array)->scope) { - zend_error(E_ERROR, "Cannot access parent:: when no class scope is active"); - } - if (!EG(active_op_array)->scope->parent) { - zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent"); - } - ce = &(EG(active_op_array)->scope->parent); - found = (*ce != NULL?SUCCESS:FAILURE); - fci->object_pp = EG(This)?&EG(This):NULL; - EX(object) = EG(This); - calling_scope = *ce; - called_scope = EG(called_scope) ? EG(called_scope) : calling_scope; - } else if (Z_UNILEN_PP(fci->object_pp) == sizeof("static") - 1 && - ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), "static", sizeof("static") - 1) - ) { - if (!EG(called_scope)) { - zend_error(E_ERROR, "Cannot access static:: when no class scope is active"); - } - ce = &(EG(called_scope)); - found = (EG(called_scope) != NULL?SUCCESS:FAILURE); - fci->object_pp = EG(This)?&EG(This):NULL; - EX(object) = EG(This); - calling_scope = called_scope = EG(called_scope); - } else { - zend_class_entry *scope; - scope = EG(active_op_array) ? EG(active_op_array)->scope : NULL; - - found = zend_u_lookup_class(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), &ce TSRMLS_CC); - if (found == FAILURE) { - zend_error(E_ERROR, "Class '%R' not found", Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp)); - } - if (scope && EG(This) && - instanceof_function(Z_OBJCE_P(EG(This)), scope TSRMLS_CC) && - instanceof_function(scope, *ce TSRMLS_CC)) { - fci->object_pp = &EG(This); - EX(object) = EG(This); - } else { - fci->object_pp = NULL; - } - calling_scope = called_scope = *ce; - } - if (found == FAILURE) - return FAILURE; - - fci->function_table = &(*ce)->function_table; - } else { - zend_error(E_NOTICE, "Non-callable array passed to zend_call_function()"); - return FAILURE; - } - - if (fci->function_table == NULL) { - return FAILURE; - } - } - - if (Z_TYPE_P(fci->function_name) == IS_OBJECT) { - if (zend_get_closure(fci->function_name, &calling_scope, &EX(function_state).function, NULL, &fci->object_pp TSRMLS_CC) == SUCCESS) { - called_scope = calling_scope; - goto init_fci_cache; - } - } else if (Z_TYPE_P(fci->function_name) != IS_STRING && - Z_TYPE_P(fci->function_name) != IS_UNICODE - ) { - return FAILURE; - } - - if (UG(unicode) && Z_TYPE_P(fci->function_name) == IS_STRING) { - old_func_name = Z_STRVAL_P(fci->function_name); - - Z_STRVAL_P(fci->function_name) = estrndup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name)); - convert_to_unicode(fci->function_name); - } - - fname = Z_UNIVAL_P(fci->function_name); - fname_len = Z_UNILEN_P(fci->function_name); - if (Z_TYPE_P(fci->function_name) == IS_UNICODE) { - if (fname.u[0] == ':' && fname.u[0] == ':') { - fname.u += 2; - fname_len -= 2; - } - } else { - if (fname.s[0] == ':' && fname.s[0] == ':') { - fname.s += 2; - fname_len -= 2; - } - } - EX(function_state).function = NULL; - lcname = zend_u_str_case_fold(Z_TYPE_P(fci->function_name), fname, fname_len, 1, &lcname_len); - - if (!fci->object_pp && - zend_u_hash_find(fci->function_table, Z_TYPE_P(fci->function_name), lcname, lcname_len + 1, (void **) &EX(function_state).function) == SUCCESS - ) { - efree(lcname.v); - } else { - efree(lcname.v); - - cname = fname; - - if (Z_TYPE_P(fci->function_name) == IS_UNICODE) { - if ((colon.u = u_memrchr(fname.u, ':', fname_len)) != NULL && - colon.u > fname.u && - *(colon.u - 1) == ':' - ) { - clen = colon.u - fname.u - 1; - fname_len -= (clen + 2); - fname.u = colon.u + 1; - } else { - colon.u = NULL; - } - } else { - if ((colon.s = zend_memrchr(fname.s, ':', fname_len)) != NULL && - colon.s > fname.s && - *(colon.s - 1) == ':' - ) { - clen = colon.s - fname.s - 1; - fname_len -= (clen + 2); - fname.s = colon.s + 1; - } else { - colon.s = NULL; - } - } - if (colon.v != NULL) { - zend_class_entry **pce, *ce_child = NULL; - - lcname = zend_u_str_case_fold(Z_TYPE_P(fci->function_name), cname, clen, 1, &clen); - /* caution: lcname is not '\0' terminated */ - if (clen == sizeof("self") - 1 && - ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, clen, "self", sizeof("self") - 1) - ) { - if (!EG(active_op_array) || !EG(active_op_array)->scope) { - zend_error(E_ERROR, "Cannot access self:: when no class scope is active"); - } - ce_child = EG(active_op_array) ? EG(active_op_array)->scope : NULL; - called_scope = EG(called_scope) ? EG(called_scope) : ce_child; - } else if (clen == sizeof("parent") - 1 && - ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, clen, "parent", sizeof("parent") - 1) - ) { - if (!EG(active_op_array) || !EG(active_op_array)->scope) { - zend_error(E_ERROR, "Cannot access parent:: when no class scope is active"); - } - if (!EG(active_op_array)->scope->parent) { - zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent"); - } - ce_child = EG(active_op_array) && EG(active_op_array)->scope ? EG(active_op_array)->scope->parent : NULL; - called_scope = EG(called_scope) ? EG(called_scope) : ce_child; - } else if (clen == sizeof("static") - 1 && - ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, clen, "static", sizeof("static") - 1) - ) { - if (!EG(called_scope)) { - zend_error(E_ERROR, "Cannot access static:: when no class scope is active"); - } - called_scope = ce_child = EG(called_scope); - } else if (zend_u_lookup_class_ex(Z_TYPE_P(fci->function_name), lcname, clen, cname, 0, &pce TSRMLS_CC) == SUCCESS) { - called_scope = ce_child = *pce; - } - efree(lcname.v); - - if (!ce_child) { - zend_error(E_ERROR, "Cannot call method %R() or method does not exist", Z_TYPE_P(fci->function_name), Z_UNIVAL_P(fci->function_name)); - return FAILURE; - } - check_scope_or_static = calling_scope; - fci->function_table = &ce_child->function_table; - calling_scope = ce_child; - } - - if (fci->object_pp) { - if (Z_OBJ_HT_PP(fci->object_pp)->get_method == NULL) { - zend_error(E_ERROR, "Object does not support method calls"); - } - EX(function_state).function = - Z_OBJ_HT_PP(fci->object_pp)->get_method(fci->object_pp, fname, fname_len TSRMLS_CC); - if (EX(function_state).function && calling_scope != EX(function_state).function->common.scope) { - zstr function_name_lc = zend_u_str_tolower_dup(Z_TYPE_P(fci->function_name), fname, fname_len); - if (zend_u_hash_find(&calling_scope->function_table, Z_TYPE_P(fci->function_name), function_name_lc, fname_len + 1, (void **) &EX(function_state).function) == FAILURE) { - efree(function_name_lc.v); - zend_error(E_ERROR, "Cannot call method %v::%R() or method does not exist", calling_scope->name, Z_TYPE_P(fci->function_name), fname); - } - efree(function_name_lc.v); - } - } else if (calling_scope) { - if (calling_scope->get_static_method) { - EX(function_state).function = calling_scope->get_static_method(calling_scope, Z_TYPE_P(fci->function_name), fname, fname_len TSRMLS_CC); - } else { - EX(function_state).function = zend_std_get_static_method(calling_scope, Z_TYPE_P(fci->function_name), fname, fname_len TSRMLS_CC); - } - - if (((zend_internal_function*)EX(function_state).function)->handler == zend_std_call_user_call) { - fci->object_pp = &EG(This); - } - - if (check_scope_or_static && EX(function_state).function - && !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC) - && !instanceof_function(check_scope_or_static, calling_scope TSRMLS_CC)) { - zend_error(E_ERROR, "Cannot call method %R() of class %v which is not a derived from %v", Z_TYPE_P(fci->function_name), Z_UNIVAL_P(fci->function_name), calling_scope->name, check_scope_or_static->name); - return FAILURE; - } - } - } - - if (EX(function_state).function == NULL) { - /* try calling __call */ - if (calling_scope && calling_scope->__call) { - EX(function_state).function = calling_scope->__call; - /* prepare params */ - ALLOC_INIT_ZVAL(method_name); - ZVAL_STRINGL(method_name, fname.s, fname_len, 0); - - ALLOC_INIT_ZVAL(params_array); - array_init(params_array); - call_via_handler = 1; - } else { - if (old_func_name) { - efree(Z_STRVAL_P(fci->function_name)); - Z_TYPE_P(fci->function_name) = IS_STRING; - Z_STRVAL_P(fci->function_name) = old_func_name; - } - return FAILURE; - } - } - -init_fci_cache: - if (fci_cache && - (EX(function_state).function->type != ZEND_INTERNAL_FUNCTION || - ((zend_internal_function*)EX(function_state).function)->handler != zend_std_call_user_call) - ) { - fci_cache->function_handler = EX(function_state).function; - fci_cache->object_pp = fci->object_pp; - fci_cache->calling_scope = calling_scope; - fci_cache->called_scope = called_scope; - fci_cache->initialized = 1; - } - } else { - EX(function_state).function = fci_cache->function_handler; - calling_scope = fci_cache->calling_scope; - called_scope = fci_cache->called_scope; - fci->object_pp = fci_cache->object_pp; - EX(object) = fci->object_pp ? *fci->object_pp : NULL; - if (fci->object_pp && *fci->object_pp && Z_TYPE_PP(fci->object_pp) == IS_OBJECT - && (!EG(objects_store).object_buckets || !EG(objects_store).object_buckets[Z_OBJ_HANDLE_PP(fci->object_pp)].valid)) { - return FAILURE; - } + zend_fcall_info_cache fci_cache_local; + zval callable_name; + char *error = NULL; + + if (!fci_cache) { + fci_cache = &fci_cache_local; + } + + if (!zend_is_callable_ex(fci->function_name, fci->object_pp, IS_CALLABLE_CHECK_SILENT, &callable_name, fci_cache, &error TSRMLS_CC)) { + if (error) { + zend_error(E_WARNING, "Invalid callback %Z, %s", callable_name, error); + efree(error); + } + zval_dtor(&callable_name); + return FAILURE; + } else if (error) { + /* Capitalize the first latter of the error message */ + if (error[0] >= 'a' && error[0] <= 'z') { + error[0] += ('A' - 'a'); + } + zend_error(E_STRICT, "%s", error); + efree(error); + } + zval_dtor(&callable_name); + } + + EX(function_state).function = fci_cache->function_handler; + calling_scope = fci_cache->calling_scope; + called_scope = fci_cache->called_scope; + fci->object_pp = fci_cache->object_pp; + EX(object) = fci->object_pp ? *fci->object_pp : NULL; + if (fci->object_pp && *fci->object_pp && Z_TYPE_PP(fci->object_pp) == IS_OBJECT + && (!EG(objects_store).object_buckets || !EG(objects_store).object_buckets[Z_OBJ_HANDLE_PP(fci->object_pp)].valid)) { + return FAILURE; } if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) { @@ -1096,11 +825,7 @@ init_fci_cache: } } - if (call_via_handler) { - ZEND_VM_STACK_GROW_IF_NEEDED(2 + 1); - } else { - ZEND_VM_STACK_GROW_IF_NEEDED(fci->param_count + 1); - } + ZEND_VM_STACK_GROW_IF_NEEDED(fci->param_count + 1); for (i=0; iparam_count; i++) { zval *param; @@ -1122,10 +847,6 @@ init_fci_cache: Z_STRVAL_P(fci->function_name) = old_func_name; } - if (call_via_handler) { - zval_ptr_dtor(&method_name); - zval_ptr_dtor(¶ms_array); - } zend_error(E_WARNING, "Parameter %d to %v%s%v() expected to be a reference, value given", i+1, EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name : EMPTY_ZSTR, @@ -1151,17 +872,7 @@ init_fci_cache: *param = **(fci->params[i]); INIT_PZVAL(param); } - if (call_via_handler) { - add_next_index_zval(params_array, param); - } else { - zend_vm_stack_push_nocheck(param TSRMLS_CC); - } - } - - if (call_via_handler) { - zend_vm_stack_push_nocheck(method_name TSRMLS_CC); - zend_vm_stack_push_nocheck(params_array TSRMLS_CC); - fci->param_count = 2; + zend_vm_stack_push_nocheck(param TSRMLS_CC); } EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C); @@ -1199,19 +910,6 @@ init_fci_cache: } } else { EG(This) = NULL; - if (calling_scope && !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) { - int severity; - char *verb; - if (EX(function_state).function->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - severity = E_STRICT; - verb = "should not"; - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - severity = E_ERROR; - verb = "cannot"; - } - zend_error(severity, "Non-static method %v::%v() %s be called statically", calling_scope->name, EX(function_state).function->common.function_name, verb); - } } EX(prev_execute_data) = EG(current_execute_data); @@ -1248,6 +946,8 @@ init_fci_cache: EG(return_value_ptr_ptr)=original_return_value; EG(opline_ptr) = original_opline_ptr; } else { + int call_via_handler = (EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0; + ALLOC_INIT_ZVAL(*fci->retval_ptr_ptr); if (EX(function_state).function->common.scope) { EG(scope) = EX(function_state).function->common.scope; @@ -1263,12 +963,13 @@ init_fci_cache: zval_ptr_dtor(fci->retval_ptr_ptr); *fci->retval_ptr_ptr = NULL; } + + if (call_via_handler) { + /* We must re-initialize function again */ + fci_cache->initialized = 0; + } } zend_vm_stack_clear_multiple(TSRMLS_C); - if (call_via_handler) { - zval_ptr_dtor(&method_name); - zval_ptr_dtor(¶ms_array); - } if (EG(This)) { zval_ptr_dtor(&EG(This)); diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 4e2d7e1d44..7f3486683f 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -803,7 +803,7 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, zstr method_ call_user_call->arg_info = NULL; call_user_call->num_args = 0; call_user_call->scope = zobj->ce; - call_user_call->fn_flags = 0; + call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER; if (UG(unicode)) { call_user_call->function_name.u = eustrndup(method_name.u, method_len); } else { @@ -939,7 +939,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_uc call_user_call->arg_info = NULL; call_user_call->num_args = 0; call_user_call->scope = ce; - call_user_call->fn_flags = 0; + call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER; if (UG(unicode)) { call_user_call->function_name.u = eustrndup(function_name_strval.u, function_name_strlen); } else { @@ -957,7 +957,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_uc callstatic_user_call->arg_info = NULL; callstatic_user_call->num_args = 0; callstatic_user_call->scope = ce; - callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC; + callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER; if (UG(unicode)) { callstatic_user_call->function_name.u = eustrndup(function_name_strval.u, function_name_strlen); @@ -970,12 +970,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_uc return (zend_function *)callstatic_user_call; } else { - zstr class_name = ce->name; - - if (!class_name.v) { - class_name.u = EMPTY_STR; - } - zend_error(E_ERROR, "Call to undefined method %R::%R()", type, class_name, type, function_name_strval); + return NULL; } } efree(lc_function_name.v); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 4a70eeda9b..d670342cc8 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2035,6 +2035,9 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS } else { EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC); } + if (!EX(fbc)) { + zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval); + } } if (OP2_TYPE != IS_CONST) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 874ac129ef..f5c5e6673d 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2721,6 +2721,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( } else { EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC); } + if (!EX(fbc)) { + zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval); + } } if (IS_CONST != IS_CONST) { @@ -3322,6 +3325,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE } else { EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC); } + if (!EX(fbc)) { + zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval); + } } if (IS_TMP_VAR != IS_CONST) { @@ -3799,6 +3805,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE } else { EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC); } + if (!EX(fbc)) { + zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval); + } } if (IS_VAR != IS_CONST) { @@ -4032,6 +4041,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER } else { EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC); } + if (!EX(fbc)) { + zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval); + } } if (IS_UNUSED != IS_CONST) { @@ -4477,6 +4489,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN } else { EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC); } + if (!EX(fbc)) { + zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval); + } } if (IS_CV != IS_CONST) { @@ -10720,6 +10735,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE } else { EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC); } + if (!EX(fbc)) { + zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval); + } } if (IS_CONST != IS_CONST) { @@ -12616,6 +12634,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND } else { EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC); } + if (!EX(fbc)) { + zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval); + } } if (IS_TMP_VAR != IS_CONST) { @@ -14488,6 +14509,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND } else { EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC); } + if (!EX(fbc)) { + zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval); + } } if (IS_VAR != IS_CONST) { @@ -15452,6 +15476,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z } else { EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC); } + if (!EX(fbc)) { + zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval); + } } if (IS_UNUSED != IS_CONST) { @@ -16974,6 +17001,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ } else { EX(fbc) = zend_std_get_static_method(ce, function_name_type, function_name_strval, function_name_strlen TSRMLS_CC); } + if (!EX(fbc)) { + zend_error(E_ERROR, "Call to undefined method %v::%R()", ce->name, function_name_type, function_name_strval); + } } if (IS_CV != IS_CONST) { diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index d38fe66024..7234a7ef12 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -1279,7 +1279,7 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *c params[0] = &reflector_ptr; params[1] = &output_ptr; - ZVAL_ASCII_STRINGL(&fname, "export", sizeof("export") - 1, 1); + ZVAL_ASCII_STRINGL(&fname, "reflection::export", sizeof("reflection::export") - 1, 1); fci.function_table = &reflection_ptr->function_table; fci.function_name = &fname; fci.object_pp = NULL; diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index ebacf6db68..f8fa3a5a60 100755 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -453,7 +453,7 @@ PHP_FUNCTION(spl_autoload_register) zval_dtor(&ztmp); } - if (!zend_is_callable_ex(zcallable, IS_CALLABLE_STRICT, &zfunc_name, &fcc, &error TSRMLS_CC)) { + if (!zend_is_callable_ex(zcallable, NULL, IS_CALLABLE_STRICT, &zfunc_name, &fcc, &error TSRMLS_CC)) { alfi.ce = fcc.calling_scope; alfi.func_ptr = fcc.function_handler; obj_ptr = fcc.object_pp; @@ -583,7 +583,7 @@ PHP_FUNCTION(spl_autoload_unregister) return; } - if (!zend_is_callable_ex(zcallable, IS_CALLABLE_CHECK_SYNTAX_ONLY, &zfunc_name, &fcc, &error TSRMLS_CC)) { + if (!zend_is_callable_ex(zcallable, NULL, IS_CALLABLE_CHECK_SYNTAX_ONLY, &zfunc_name, &fcc, &error TSRMLS_CC)) { zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Unable to unregister invalid function (%s)", error); if (error) { efree(error); diff --git a/ext/spl/tests/spl_autoload_007.phpt b/ext/spl/tests/spl_autoload_007.phpt index 3b6b3b90c1..3852578cf9 100755 --- a/ext/spl/tests/spl_autoload_007.phpt +++ b/ext/spl/tests/spl_autoload_007.phpt @@ -57,7 +57,7 @@ foreach($funcs as $idx => $func) --EXPECTF-- unicode(22) "MyAutoLoader::notExist" -Function 'MyAutoLoader::notExist' not found (class 'MyAutoLoader' does not have a method 'notexist') +Function 'MyAutoLoader::notExist' not found (class 'MyAutoLoader' does not have a method 'notExist') unicode(22) "MyAutoLoader::noAccess" Function 'MyAutoLoader::noAccess' not callable (cannot access protected method MyAutoLoader::noAccess()) @@ -74,7 +74,7 @@ array(2) { [1]=> unicode(8) "notExist" } -Passed array does not specify an existing static method (class 'MyAutoLoader' does not have a method 'notexist') +Passed array does not specify an existing static method (class 'MyAutoLoader' does not have a method 'notExist') array(2) { [0]=> @@ -107,7 +107,7 @@ array(2) { [1]=> unicode(8) "notExist" } -Passed array does not specify an existing method (class 'MyAutoLoader' does not have a method 'notexist') +Passed array does not specify an existing method (class 'MyAutoLoader' does not have a method 'notExist') array(2) { [0]=> diff --git a/ext/standard/tests/array/array_map_object1.phpt b/ext/standard/tests/array/array_map_object1.phpt index 64b91fbec9..6565c3fee9 100644 --- a/ext/standard/tests/array/array_map_object1.phpt +++ b/ext/standard/tests/array/array_map_object1.phpt @@ -70,7 +70,7 @@ class ChildClass extends AbstractClass { private $var3; public function emptyFunction() { - echo "defined in child"; + echo "defined in child\n"; } } test(array('ChildClass', 'emptyFunction'), array(1, 2)); @@ -80,7 +80,7 @@ class FinalClass { private $var4; final function finalMethod() { - echo "This function can't be overloaded"; + echo "This function can't be overloaded\n"; } } test(array('FinalClass', 'finalMethod'), array(1, 2)); @@ -128,10 +128,6 @@ test(array('InterClass', 'square'), array(1, 2)); SimpleClass::square Strict Standards: array_map() expects parameter 1 to be a valid callback, non-static method SimpleClass::square() should not be called statically in %sarray_map_object1.php on line %d - -Strict Standards: Non-static method SimpleClass::square() should not be called statically in %sarray_map_object1.php on line %d - -Strict Standards: Non-static method SimpleClass::square() should not be called statically in %sarray_map_object1.php on line %d array(2) { [0]=> int(1) @@ -161,11 +157,9 @@ NULL ChildClass::emptyFunction Strict Standards: array_map() expects parameter 1 to be a valid callback, non-static method ChildClass::emptyFunction() should not be called statically in %sarray_map_object1.php on line %d - -Strict Standards: Non-static method ChildClass::emptyFunction() should not be called statically in %sarray_map_object1.php on line %d defined in child -Strict Standards: Non-static method ChildClass::emptyFunction() should not be called statically in %sarray_map_object1.php on line %d -defined in childarray(2) { +defined in child +array(2) { [0]=> NULL [1]=> @@ -176,11 +170,9 @@ defined in childarray(2) { FinalClass::finalMethod Strict Standards: array_map() expects parameter 1 to be a valid callback, non-static method FinalClass::finalMethod() should not be called statically in %sarray_map_object1.php on line %d - -Strict Standards: Non-static method FinalClass::finalMethod() should not be called statically in %sarray_map_object1.php on line %d This function can't be overloaded -Strict Standards: Non-static method FinalClass::finalMethod() should not be called statically in %sarray_map_object1.php on line %d -This function can't be overloadedarray(2) { +This function can't be overloaded +array(2) { [0]=> NULL [1]=> diff --git a/ext/standard/tests/array/array_map_object3.phpt b/ext/standard/tests/array/array_map_object3.phpt index d1a6d80629..9424c44110 100644 --- a/ext/standard/tests/array/array_map_object3.phpt +++ b/ext/standard/tests/array/array_map_object3.phpt @@ -74,7 +74,7 @@ array(3) { } -- accessing child method from parent class -- -Warning: array_map() expects parameter 1 to be a valid callback, class 'ParentClass' does not have a method 'staticchild' in %s on line %d +Warning: array_map() expects parameter 1 to be a valid callback, class 'ParentClass' does not have a method 'staticChild' in %s on line %d NULL -- accessing parent method using child class object -- array(3) { @@ -87,6 +87,6 @@ array(3) { } -- accessing child method using parent class object -- -Warning: array_map() expects parameter 1 to be a valid callback, class 'ParentClass' does not have a method 'staticchild' in %s on line %d +Warning: array_map() expects parameter 1 to be a valid callback, class 'ParentClass' does not have a method 'staticChild' in %s on line %d NULL Done diff --git a/ext/standard/tests/general_functions/bug40398.phpt b/ext/standard/tests/general_functions/bug40398.phpt index c63fcfd0c8..11fdde2c51 100755 --- a/ext/standard/tests/general_functions/bug40398.phpt +++ b/ext/standard/tests/general_functions/bug40398.phpt @@ -77,16 +77,8 @@ new Derived_6('6'); --EXPECTF-- Base::__construct(1) Base::__construct(2) - -Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method Base::__construct() cannot be called statically, assuming $this from compatible context Derived_3 in %s on line %d Base::__construct(3) - -Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method Base::__construct() cannot be called statically, assuming $this from compatible context Derived_4 in %s on line %d Base::__construct(4) - -Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method Base::__construct() cannot be called statically, assuming $this from compatible context Derived_5 in %s on line %d Base::__construct(5) - -Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method Base::__construct() cannot be called statically, assuming $this from compatible context Derived_6 in %s on line %d Base::__construct(6) ===DONE=== diff --git a/ext/standard/tests/general_functions/callbacks_001.phpt b/ext/standard/tests/general_functions/callbacks_001.phpt index 852bb46ecf..a58f19d932 100644 --- a/ext/standard/tests/general_functions/callbacks_001.phpt +++ b/ext/standard/tests/general_functions/callbacks_001.phpt @@ -97,12 +97,8 @@ B|who2 A ===FOREIGN=== parent|who - -Strict Standards: call_user_func() expects parameter 1 to be a valid callback, non-static method O::who() should not be called statically, assuming $this from compatible context P in %s on line %d O P|parent::who - -Strict Standards: call_user_func() expects parameter 1 to be a valid callback, non-static method O::who() should not be called statically, assuming $this from compatible context P in %s on line %d O $this|O::who O -- 2.40.0