From ed84bff44569d3b7e2f79255208e69bbe755d6a9 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 16 Jun 2015 11:24:35 +0300 Subject: [PATCH] Complete fix for problems related to bug #69802 --- Zend/tests/bug69802.phpt | 16 +++++++++++++++- Zend/zend_closures.c | 5 +++-- Zend/zend_compile.h | 3 +++ ext/reflection/php_reflection.c | 30 +++++++++++++++++------------- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/Zend/tests/bug69802.phpt b/Zend/tests/bug69802.phpt index 6143b0be66..ed0430f6d2 100644 --- a/Zend/tests/bug69802.phpt +++ b/Zend/tests/bug69802.phpt @@ -2,12 +2,26 @@ Bug #69802 (Reflection on Closure::__invoke borks type hint class name) --FILE-- getParameters()[0]->getName()); var_dump($r->getParameters()[0]->getClass()); +echo $r->getParameters()[0], "\n"; +echo $r->getReturnType(),"\n"; +echo $r,"\n"; ?> --EXPECT-- +string(1) "x" object(ReflectionClass)#4 (1) { ["name"]=> string(8) "stdClass" } +Parameter #0 [ stdClass $x ] +stdClass +Method [ public method __invoke ] { + + - Parameters [1] { + Parameter #0 [ stdClass $x ] + } + - Return [ stdClass ] +} diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 2eeaec639d..2d38fb2f4c 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -210,10 +210,11 @@ ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *object) /* { /* We return ZEND_INTERNAL_FUNCTION, but arg_info representation is the * same as for ZEND_USER_FUNCTION (uses zend_string* instead of char*). * This is not a problem, because ZEND_ACC_HAS_TYPE_HINTS is never set, - * and we won't check arguments on internal function */ + * and we won't check arguments on internal function. We also set + * ZEND_ACC_USER_ARG_INFO flag to prevent invalid usage by Reflection */ invoke->type = ZEND_INTERNAL_FUNCTION; invoke->internal_function.fn_flags = - ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | (closure->func.common.fn_flags & keep_flags); + ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | ZEND_ACC_USER_ARG_INFO | (closure->func.common.fn_flags & keep_flags); invoke->internal_function.handler = ZEND_MN(Closure___invoke); invoke->internal_function.module = 0; invoke->internal_function.scope = zend_ce_closure; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index eccbb84aff..1ed6e236b0 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -214,6 +214,9 @@ typedef struct _zend_try_catch_element { #define ZEND_ACC_DTOR 0x4000 #define ZEND_ACC_CLONE 0x8000 +/* method flag used by Closure::__invoke() */ +#define ZEND_ACC_USER_ARG_INFO 0x80 + /* method flag (bc only), any method that has this flag can be used statically and non statically. */ #define ZEND_ACC_ALLOW_STATIC 0x10000 diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index c8c5a527ab..195ea70fc0 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -667,7 +667,8 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg } if (arg_info->class_name) { string_printf(str, "%s ", - (fptr->type == ZEND_INTERNAL_FUNCTION) ? + (fptr->type == ZEND_INTERNAL_FUNCTION && + !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) ? ((zend_internal_arg_info*)arg_info)->class_name : arg_info->class_name->val); if (arg_info->allow_null) { @@ -687,7 +688,8 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg } if (arg_info->name) { string_printf(str, "$%s", - (fptr->type == ZEND_INTERNAL_FUNCTION) ? + (fptr->type == ZEND_INTERNAL_FUNCTION && + !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) ? ((zend_internal_arg_info*)arg_info)->name : arg_info->name->val); } else { @@ -891,7 +893,8 @@ static void _function_string(string *str, zend_function *fptr, zend_class_entry string_printf(str, " %s- Return [ ", indent); if (fptr->common.arg_info[-1].class_name) { string_printf(str, "%s ", - (fptr->type == ZEND_INTERNAL_FUNCTION) ? + (fptr->type == ZEND_INTERNAL_FUNCTION && + !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) ? ((zend_internal_arg_info*)(fptr->common.arg_info - 1))->class_name : fptr->common.arg_info[-1].class_name->val); if (fptr->common.arg_info[-1].allow_null) { @@ -1224,7 +1227,8 @@ static void reflection_parameter_factory(zend_function *fptr, zval *closure_obje zval name; if (arg_info->name) { - if (fptr->type == ZEND_INTERNAL_FUNCTION) { + if (fptr->type == ZEND_INTERNAL_FUNCTION && + !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { ZVAL_STRING(&name, ((zend_internal_arg_info*)arg_info)->name); } else { ZVAL_STR_COPY(&name, arg_info->name); @@ -2340,7 +2344,6 @@ ZEND_METHOD(reflection_parameter, __construct) uint32_t num_args; zend_class_entry *ce = NULL; zend_bool is_closure = 0; - zend_bool is_invoke = 0; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zz", &reference, ¶meter) == FAILURE) { return; @@ -2405,7 +2408,6 @@ ZEND_METHOD(reflection_parameter, __construct) { /* nothing to do. don't set is_closure since is the invoke handler, not the closure itself */ - is_invoke = 1; } else if ((fptr = zend_hash_str_find_ptr(&ce->function_table, lcname, lcname_len)) == NULL) { efree(lcname); zend_throw_exception_ex(reflection_exception_ptr, 0, @@ -2462,7 +2464,8 @@ ZEND_METHOD(reflection_parameter, __construct) position= -1; convert_to_string_ex(parameter); - if (!is_invoke && fptr->type == ZEND_INTERNAL_FUNCTION) { + if (fptr->type == ZEND_INTERNAL_FUNCTION && + !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { for (i = 0; i < num_args; i++) { if (arg_info[i].name) { if (strcmp(((zend_internal_arg_info*)arg_info)[i].name, Z_STRVAL_P(parameter)) == 0) { @@ -2498,7 +2501,8 @@ ZEND_METHOD(reflection_parameter, __construct) } if (arg_info[position].name) { - if (fptr->type == ZEND_INTERNAL_FUNCTION) { + if (fptr->type == ZEND_INTERNAL_FUNCTION && + !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { ZVAL_STRING(&name, ((zend_internal_arg_info*)arg_info)[position].name); } else { ZVAL_STR_COPY(&name, arg_info[position].name); @@ -2621,9 +2625,7 @@ ZEND_METHOD(reflection_parameter, getClass) size_t class_name_len; if (param->fptr->type == ZEND_INTERNAL_FUNCTION && - /* Closure::__invoke() reuses arg_info of user function and - * don't set ZEND_ACC_HAS_TYPE_HINTS flag */ - (param->fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + !(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { class_name = ((zend_internal_arg_info*)param->arg_info)->class_name; class_name_len = strlen(class_name); } else { @@ -2698,7 +2700,8 @@ ZEND_METHOD(reflection_parameter, getType) } GET_REFLECTION_OBJECT_PTR(param); - if ((param->fptr->type == ZEND_INTERNAL_FUNCTION ? + if (((param->fptr->type == ZEND_INTERNAL_FUNCTION && + !(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) ? ((zend_internal_arg_info*)param->arg_info)->type_hint : param->arg_info->type_hint) == 0) { @@ -2993,7 +2996,8 @@ ZEND_METHOD(reflection_type, __toString) case IS_ARRAY: RETURN_STRINGL("array", sizeof("array") - 1); case IS_CALLABLE: RETURN_STRINGL("callable", sizeof("callable") - 1); case IS_OBJECT: - if (param->fptr->type == ZEND_INTERNAL_FUNCTION) { + if (param->fptr->type == ZEND_INTERNAL_FUNCTION && + !(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { if (!(param->fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { RETURN_STRING(((zend_internal_arg_info*)param->arg_info)->class_name); } -- 2.40.0