dmitry                                   Mon, 30 Nov 2009 11:39:53 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=291488

Log:
Fixed bug #50261 (Crash When Calling Parent Constructor with call_user_func())

Bug: http://bugs.php.net/50261 (Assigned) Crash When Calling Parent Constructor 
with call_user_func()
      
Changed paths:
    U   php/php-src/branches/PHP_5_3/NEWS
    U   php/php-src/branches/PHP_5_3/Zend/zend_API.c
    U   php/php-src/trunk/Zend/zend_API.c

Modified: php/php-src/branches/PHP_5_3/NEWS
===================================================================
--- php/php-src/branches/PHP_5_3/NEWS	2009-11-30 11:18:00 UTC (rev 291487)
+++ php/php-src/branches/PHP_5_3/NEWS	2009-11-30 11:39:53 UTC (rev 291488)
@@ -30,6 +30,8 @@
   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

Modified: php/php-src/branches/PHP_5_3/Zend/zend_API.c
===================================================================
--- php/php-src/branches/PHP_5_3/Zend/zend_API.c	2009-11-30 11:18:00 UTC (rev 291487)
+++ php/php-src/branches/PHP_5_3/Zend/zend_API.c	2009-11-30 11:39:53 UTC (rev 291488)
@@ -2117,7 +2117,7 @@
 #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 @@
 }
 /* }}} */

-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 @@
 			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 @@
 			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 @@
 		} 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_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 @@
 			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 @@
 	}

 	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 @@
 	} 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 @@
 				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 @@
 			{
 				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 @@
 							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 @@
 						}
 					}

-					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 &&

Modified: php/php-src/trunk/Zend/zend_API.c
===================================================================
--- php/php-src/trunk/Zend/zend_API.c	2009-11-30 11:18:00 UTC (rev 291487)
+++ php/php-src/trunk/Zend/zend_API.c	2009-11-30 11:39:53 UTC (rev 291488)
@@ -2710,13 +2710,14 @@
 }
 /* }}} */

-static int zend_is_callable_check_class(zend_uchar utype, const zstr name, int name_len, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */
+static int zend_is_callable_check_class(zend_uchar utype, const zstr name, int name_len, zend_fcall_info_cache *fcc, int *strict_class, char **error TSRMLS_DC) /* {{{ */
 {
 	int ret = 0;
 	zend_class_entry **pce;
 	unsigned int lcname_len;
 	zstr lcname = zend_u_str_case_fold(utype, name, name_len, 1, &lcname_len);

+	*strict_class = 0;
 	if (lcname_len == sizeof("self") - 1 &&
 	    ZEND_U_EQUAL(utype, lcname, lcname_len, "self", sizeof("self") - 1)) {
 		if (!EG(scope)) {
@@ -2727,6 +2728,7 @@
 			if (!fcc->object_ptr) {
 				fcc->object_ptr = EG(This);
 			}
+			*strict_class = 1;
 			ret = 1;
 		}
 	} else if (lcname_len == sizeof("parent") - 1 &&
@@ -2741,6 +2743,7 @@
 			if (!fcc->object_ptr) {
 				fcc->object_ptr = EG(This);
 			}
+			*strict_class = 1;
 			ret = 1;
 		}
 	} else if (lcname_len == sizeof("static") - 1 &&
@@ -2767,6 +2770,7 @@
 		} else {
 			fcc->called_scope = fcc->object_ptr ? Z_OBJCE_P(fcc->object_ptr) : fcc->calling_scope;
 		}
+		*strict_class = 1;
 		ret = 1;
 	} else {
 		if (error) {
@@ -2785,7 +2789,7 @@
 }
 /* }}} */

-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;
@@ -2864,7 +2868,7 @@
 			EG(scope) = ce_org;
 		}

-		if (!zend_is_callable_check_class(Z_TYPE_P(callable), Z_UNIVAL_P(callable), clen, fcc, error TSRMLS_CC)) {
+		if (!zend_is_callable_check_class(Z_TYPE_P(callable), Z_UNIVAL_P(callable), clen, fcc, &strict_class, error TSRMLS_CC)) {
 			EG(scope) = last_scope;
 			return 0;
 		}
@@ -2890,7 +2894,15 @@
 	}

 	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) {
+	if (strict_class &&
+	    fcc->calling_scope &&
+	    mlen == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1 &&
+	    ZEND_U_EQUAL(Z_TYPE_P(callable), lmname, lmlen, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1)) {
+		fcc->function_handler = fcc->calling_scope->constructor;
+		if (fcc->function_handler) {
+			retval = 1;
+		}
+	} else if (zend_u_hash_find(ftable, Z_TYPE_P(callable), lmname, lmlen+1, (void**)&fcc->function_handler) == SUCCESS) {
 		retval = 1;
 		if ((fcc->function_handler->op_array.fn_flags & ZEND_ACC_CHANGED) &&
 		    EG(scope) &&
@@ -2924,7 +2936,25 @@
 	} 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;
+				if (Z_TYPE_P(callable) == IS_STRING) {
+					fcc->function_handler->internal_function.function_name.s = estrndup(mname.s, lmlen);
+				} else {
+					fcc->function_handler->internal_function.function_name.u = eustrndup(mname.u, lmlen);
+				}
+				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) {
 				zstr method = mname;
 				int method_len = mlen;

@@ -2936,6 +2966,19 @@
 					efree(method.v);
 				}
 				if (fcc->function_handler) {
+					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.v);
+							}
+							efree(fcc->function_handler);
+						}
+					} else {
+						retval = 1;
+						call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
+					}
 					retval = 1;
 					call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
 				}
@@ -3099,7 +3142,7 @@
 				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 &&
@@ -3117,6 +3160,7 @@
 			{
 				zval **method;
 				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) == SUCCESS &&
@@ -3160,7 +3204,7 @@
 							return 1;
 						}

-						if (!zend_is_callable_check_class(Z_TYPE_PP(obj), Z_UNIVAL_PP(obj), Z_UNILEN_PP(obj), fcc, error TSRMLS_CC)) {
+						if (!zend_is_callable_check_class(Z_TYPE_PP(obj), Z_UNIVAL_PP(obj), Z_UNILEN_PP(obj), fcc, &strict_class, error TSRMLS_CC)) {
 							return 0;
  						}
 					} else {
@@ -3198,7 +3242,7 @@
 						}
 					}

-					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 &&
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to