From af05ce0af6d35e668de297fc4961fa738272f13c Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Sat, 26 Jul 2008 13:14:04 +0000 Subject: 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/zend_execute_API.c | 326 ++++++------------------------------------------ 1 file changed, 35 insertions(+), 291 deletions(-) (limited to 'Zend/zend_execute_API.c') diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 8a676dcea0..360e403b1c 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -685,15 +685,8 @@ 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; - unsigned int clen; - int fname_len; - char *colon, *fname, *cname, *lcname; *fci->retval_ptr_ptr = NULL; @@ -728,261 +721,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; + zend_fcall_info_cache fci_cache_local; + char *callable_name; + char *error = NULL; - 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) { - zend_class_entry **ce; - int found = FAILURE; - - if (strcmp(Z_STRVAL_PP(fci->object_pp), "self") == 0) { - 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 (strcmp(Z_STRVAL_PP(fci->object_pp), "parent") == 0 && EG(active_op_array)) { - - 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_STRLEN_PP(fci->object_pp) == sizeof("static") - 1 && - !memcmp(Z_STRVAL_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_lookup_class(Z_STRVAL_PP(fci->object_pp), Z_STRLEN_PP(fci->object_pp), &ce TSRMLS_CC); - if (found == FAILURE) { - zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL_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 (!fci_cache) { + fci_cache = &fci_cache_local; } - 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; + if (!zend_is_callable_ex(fci->function_name, fci->object_pp, IS_CALLABLE_CHECK_SILENT, &callable_name, NULL, fci_cache, &error TSRMLS_CC)) { + if (error) { + zend_error(E_WARNING, "Invalid callback %s, %s", callable_name, error); + efree(error); } - } else if (Z_TYPE_P(fci->function_name) != IS_STRING) { + efree(callable_name); return FAILURE; - } - - fname = Z_STRVAL_P(fci->function_name); - fname_len = Z_STRLEN_P(fci->function_name); - if (fname[0] == ':' && fname[1] == ':') { - fname += 2; - fname_len -=2; - } - EX(function_state).function = NULL; - lcname = zend_str_tolower_dup(fname, fname_len); - - if (!fci->object_pp && - zend_hash_find(fci->function_table, lcname, fname_len + 1, (void **)&EX(function_state).function) == SUCCESS - ) { - efree(lcname); - } else { - efree(lcname); - - cname = fname; - - if ((colon = zend_memrchr(fname, ':', fname_len)) != NULL && - colon > fname && - *(colon - 1) == ':' - ) { - zend_class_entry **pce, *ce_child = NULL; - - clen = colon - fname - 1; - fname_len -= (clen + 2); - fname = colon + 1; - - lcname = zend_str_tolower_dup(cname, clen); - /* caution: lcname is not '\0' terminated */ - if (clen == sizeof("self") - 1 && - memcmp(lcname, "self", sizeof("self") - 1) == 0 - ) { - 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 && - memcmp(lcname, "parent", sizeof("parent") - 1) == 0 - ) { - 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 && - memcmp(lcname, "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_lookup_class(lcname, clen, &pce TSRMLS_CC) == SUCCESS) { - called_scope = ce_child = *pce; - } - efree(lcname); - - if (!ce_child) { - zend_error(E_ERROR, "Cannot call method %s() or method does not exist", Z_STRVAL_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) { - char *function_name_lc = zend_str_tolower_dup(fname, fname_len); - if (zend_hash_find(&calling_scope->function_table, function_name_lc, fname_len + 1, (void **) &EX(function_state).function) == FAILURE) { - efree(function_name_lc); - zend_error(E_ERROR, "Cannot call method %s::%s() or method does not exist", calling_scope->name, fname); - } - efree(function_name_lc); - } - } else if (calling_scope) { - if (calling_scope->get_static_method) { - EX(function_state).function = calling_scope->get_static_method(calling_scope, fname, fname_len TSRMLS_CC); - } else { - EX(function_state).function = zend_std_get_static_method(calling_scope, 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 %s() of class %s which is not a derived from %s", Z_STRVAL_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, fname_len, 0); - - ALLOC_INIT_ZVAL(params_array); - array_init(params_array); - call_via_handler = 1; - } else { - 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); } + efree(callable_name); + } -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; - } + 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)) { @@ -997,11 +769,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; @@ -1019,10 +787,6 @@ init_fci_cache: zend_vm_stack_clear_multiple(TSRMLS_C); } - if (call_via_handler) { - zval_ptr_dtor(&method_name); - zval_ptr_dtor(¶ms_array); - } zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", i+1, EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name : "", @@ -1049,17 +813,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); @@ -1097,19 +851,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 %s::%s() %s be called statically", calling_scope->name, EX(function_state).function->common.function_name, verb); - } } EX(prev_execute_data) = EG(current_execute_data); @@ -1146,6 +887,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; @@ -1161,12 +904,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)); -- cgit v1.2.1