From 5c56abb6e383d5adaf190cbd93406ca307b3a627 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 30 Nov 2009 11:39:53 +0000 Subject: [PATCH] Fixed bug #50261 (Crash When Calling Parent Constructor with call_user_func()) --- NEWS | 2 ++ Zend/zend_API.c | 60 ++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index 612587432c..43fa135faf 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,8 @@ PHP NEWS calling function). (Felipe) - Fixed bug #50267 (get_browser(null) does not use HTTP_USER_AGENT). (Jani) - Fixed bug #50266 (conflicting types for llabs). (Jani) +- Fixed bug #50261 (Crash When Calling Parent Constructor with + call_user_func()). (Dmitry) - Fixed bug #50255 (isset() and empty() silently casts array to object). (Felipe) - Fixed bug #50240 (pdo_mysql.default_socket in php.ini shouldn't used diff --git a/Zend/zend_API.c b/Zend/zend_API.c index d2824bfdc8..7397a267aa 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2117,7 +2117,7 @@ void module_destructor(zend_module_entry *module) /* {{{ */ #if HAVE_LIBDL #if !(defined(NETWARE) && defined(APACHE_1_BUILD)) if (module->handle) { - DL_UNLOAD(module->handle); +// DL_UNLOAD(module->handle); } #endif #endif @@ -2335,12 +2335,13 @@ ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_ } /* }}} */ -static int zend_is_callable_check_class(const char *name, int name_len, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */ +static int zend_is_callable_check_class(const char *name, int name_len, zend_fcall_info_cache *fcc, int *strict_class, char **error TSRMLS_DC) /* {{{ */ { int ret = 0; zend_class_entry **pce; char *lcname = zend_str_tolower_dup(name, name_len); + *strict_class = 0; if (name_len == sizeof("self") - 1 && !memcmp(lcname, "self", sizeof("self") - 1)) { if (!EG(scope)) { @@ -2365,6 +2366,7 @@ static int zend_is_callable_check_class(const char *name, int name_len, zend_fca if (!fcc->object_ptr) { fcc->object_ptr = EG(This); } + *strict_class = 1; ret = 1; } } else if (name_len == sizeof("static") - 1 && @@ -2377,6 +2379,7 @@ static int zend_is_callable_check_class(const char *name, int name_len, zend_fca if (!fcc->object_ptr) { fcc->object_ptr = EG(This); } + *strict_class = 1; ret = 1; } } else if (zend_lookup_class_ex(name, name_len, 1, &pce TSRMLS_CC) == SUCCESS) { @@ -2391,6 +2394,7 @@ static int zend_is_callable_check_class(const char *name, int name_len, zend_fca } else { fcc->called_scope = fcc->object_ptr ? Z_OBJCE_P(fcc->object_ptr) : fcc->calling_scope; } + *strict_class = 1; ret = 1; } else { if (error) zend_spprintf(error, 0, "class '%.*s' not found", name_len, name); @@ -2401,7 +2405,7 @@ static int zend_is_callable_check_class(const char *name, int name_len, zend_fca /* }}} */ -static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */ +static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, int strict_class, char **error TSRMLS_DC) /* {{{ */ { zend_class_entry *ce_org = fcc->calling_scope; int retval = 0; @@ -2459,7 +2463,7 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca EG(scope) = ce_org; } - if (!zend_is_callable_check_class(Z_STRVAL_P(callable), clen, fcc, error TSRMLS_CC)) { + if (!zend_is_callable_check_class(Z_STRVAL_P(callable), clen, fcc, &strict_class, error TSRMLS_CC)) { EG(scope) = last_scope; return 0; } @@ -2486,7 +2490,15 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca } lmname = zend_str_tolower_dup(mname, mlen); - if (zend_hash_find(ftable, lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS) { + if (strict_class && + fcc->calling_scope && + mlen == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1 && + !memcmp(lmname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME))) { + fcc->function_handler = fcc->calling_scope->constructor; + if (fcc->function_handler) { + retval = 1; + } + } else if (zend_hash_find(ftable, lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS) { retval = 1; if ((fcc->function_handler->op_array.fn_flags & ZEND_ACC_CHANGED) && EG(scope) && @@ -2520,11 +2532,36 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca } else { get_function_via_handler: if (fcc->object_ptr && fcc->calling_scope == ce_org) { - if (Z_OBJ_HT_P(fcc->object_ptr)->get_method) { + 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->module; + 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 = estrndup(mname, mlen); + fcc->function_handler->internal_function.pass_rest_by_reference = 0; + fcc->function_handler->internal_function.return_reference = ZEND_RETURN_VALUE; + call_via_handler = 1; + retval = 1; + } else if (Z_OBJ_HT_P(fcc->object_ptr)->get_method) { fcc->function_handler = Z_OBJ_HT_P(fcc->object_ptr)->get_method(&fcc->object_ptr, mname, mlen TSRMLS_CC); if (fcc->function_handler) { - retval = 1; - call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0; + if (strict_class && + (!fcc->function_handler->common.scope || + !instanceof_function(ce_org, fcc->function_handler->common.scope TSRMLS_CC))) { + if ((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0) { + if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) { + efree(fcc->function_handler->common.function_name); + } + efree(fcc->function_handler); + } + } else { + retval = 1; + call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0; + } } } } else if (fcc->calling_scope) { @@ -2680,7 +2717,7 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, zval *object_ptr, uint ch return 1; } - ret = zend_is_callable_check_func(check_flags, callable, fcc, error TSRMLS_CC); + ret = zend_is_callable_check_func(check_flags, callable, fcc, 0, error TSRMLS_CC); if (fcc == &fcc_local && fcc->function_handler && ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION && @@ -2698,6 +2735,7 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, zval *object_ptr, uint ch { zval **method = NULL; zval **obj = NULL; + int strict_class = 0; if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) { zend_hash_index_find(Z_ARRVAL_P(callable), 0, (void **) &obj); @@ -2725,7 +2763,7 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, zval *object_ptr, uint ch return 1; } - if (!zend_is_callable_check_class(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), fcc, error TSRMLS_CC)) { + if (!zend_is_callable_check_class(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), fcc, &strict_class, error TSRMLS_CC)) { return 0; } @@ -2757,7 +2795,7 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, zval *object_ptr, uint ch } } - ret = zend_is_callable_check_func(check_flags, *method, fcc, error TSRMLS_CC); + ret = zend_is_callable_check_func(check_flags, *method, fcc, strict_class, error TSRMLS_CC); if (fcc == &fcc_local && fcc->function_handler && ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION && -- 2.40.0