diff --git a/Zend/zend_API.c b/Zend/zend_API.c index e95276d4c80a2..10efd7ab5bb84 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2192,7 +2192,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio if (ptr->arg_info) { zend_internal_function_info *info = (zend_internal_function_info*)ptr->arg_info; - internal_function->arg_info = (zend_arg_info*)ptr->arg_info+1; + internal_function->arg_info = (zend_internal_arg_info*)ptr->arg_info+1; internal_function->num_args = ptr->num_args; /* Currently you cannot denote that the function can accept less arguments than num_args */ if (info->required_num_args == -1) { diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 6817e85f9b57d..bee797b7da6be 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -35,7 +35,7 @@ BEGIN_EXTERN_C() typedef struct _zend_function_entry { const char *fname; void (*handler)(INTERNAL_FUNCTION_PARAMETERS); - const struct _zend_arg_info *arg_info; + const struct _zend_internal_arg_info *arg_info; uint32_t num_args; uint32_t flags; } zend_function_entry; @@ -98,16 +98,16 @@ typedef struct _zend_fcall_info_cache { #define ZEND_FE_END { NULL, NULL, NULL, 0, 0 } -#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, pass_by_ref, 0, 0 }, -#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 0, 0, pass_by_ref, 0, 0 }, -#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, IS_OBJECT, pass_by_ref, allow_null, 0 }, -#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, IS_ARRAY, pass_by_ref, allow_null, 0 }, -#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, sizeof(#name)-1, NULL, 0, type_hint, pass_by_ref, allow_null, 0 }, -#define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, pass_by_ref, 0, 1 }, +#define ZEND_ARG_INFO(pass_by_ref, name) { #name, NULL, 0, pass_by_ref, 0, 0 }, +#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, NULL, 0, pass_by_ref, 0, 0 }, +#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, #classname, IS_OBJECT, pass_by_ref, allow_null, 0 }, +#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, NULL, IS_ARRAY, pass_by_ref, allow_null, 0 }, +#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, NULL, type_hint, pass_by_ref, allow_null, 0 }, +#define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) { #name, NULL, 0, pass_by_ref, 0, 1 }, #define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) \ - static const zend_arg_info name[] = { \ - { NULL, 0, NULL, required_num_args, 0, return_reference, 0, 0 }, + static const zend_internal_arg_info name[] = { \ + { (const char*)(zend_uintptr_t)(required_num_args), NULL, 0, return_reference, 0, 0 }, #define ZEND_BEGIN_ARG_INFO(name, _unused) \ ZEND_BEGIN_ARG_INFO_EX(name, 0, ZEND_RETURN_VALUE, -1) #define ZEND_END_ARG_INFO() }; diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index e4827f83b772c..bf0ba0ace4050 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -182,6 +182,7 @@ ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *object TSRML zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function)); invoke->common = closure->func.common; + /* TODO: return ZEND_INTERNAL_FUNCTION, but arg_info representation is suitable for ZEND_USER_FUNCTION ??? */ invoke->type = ZEND_INTERNAL_FUNCTION; invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | (closure->func.common.fn_flags & ZEND_ACC_RETURN_REFERENCE); invoke->internal_function.handler = ZEND_MN(Closure___invoke); @@ -370,7 +371,7 @@ static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_ if (arg_info->name) { name = zend_strpprintf(0, "%s$%s", arg_info->pass_by_reference ? "&" : "", - arg_info->name); + arg_info->name->val); } else { name = zend_strpprintf(0, "%s$param%d", arg_info->pass_by_reference ? "&" : "", diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index cfc70af590232..086c7d0db165e 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3833,14 +3833,12 @@ void zend_compile_params(zend_ast *ast TSRMLS_DC) /* {{{ */ opline->op1.num = i + 1; arg_info = &arg_infos[i]; - arg_info->name = estrndup(name->val, name->len); - arg_info->name_len = (uint32_t)name->len; + arg_info->name = zend_string_copy(name); arg_info->pass_by_reference = is_ref; arg_info->is_variadic = is_variadic; arg_info->type_hint = 0; arg_info->allow_null = 1; arg_info->class_name = NULL; - arg_info->class_name_len = 0; if (type_ast) { zend_bool has_null_default = default_ast @@ -3877,10 +3875,7 @@ void zend_compile_params(zend_ast *ast TSRMLS_DC) /* {{{ */ } arg_info->type_hint = IS_OBJECT; - arg_info->class_name = estrndup(class_name->val, class_name->len); - arg_info->class_name_len = (uint32_t)class_name->len; - - zend_string_release(class_name); + arg_info->class_name = class_name; if (default_ast && !has_null_default && !Z_CONSTANT(default_node.u.constant)) { zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index a885518caf78b..63d67660c68e1 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -245,26 +245,33 @@ typedef struct _zend_property_info { #define OBJ_PROP_TO_NUM(offset) \ ((offset - OBJ_PROP_TO_OFFSET(0)) / sizeof(zval)) +/* arg_info for internal functions */ +typedef struct _zend_internal_arg_info { + const char *name; + const char *class_name; + zend_uchar type_hint; + zend_uchar pass_by_reference; + zend_bool allow_null; + zend_bool is_variadic; +} zend_internal_arg_info; + +/* arg_info for user functions */ typedef struct _zend_arg_info { - const char *name; // TODO: convert into zend_string ??? - uint32_t name_len; - const char *class_name; // TODO: convert into zend_string ??? - uint32_t class_name_len; + zend_string *name; + zend_string *class_name; zend_uchar type_hint; zend_uchar pass_by_reference; zend_bool allow_null; zend_bool is_variadic; } zend_arg_info; -/* the following structure repeats the layout of zend_arg_info, +/* the following structure repeats the layout of zend_internal_arg_info, * but its fields have different meaning. It's used as the first element of * arg_info array to define properties of internal functions. */ typedef struct _zend_internal_function_info { - const char *_name; - uint32_t _name_len; + zend_uintptr_t required_num_args; const char *_class_name; - uint32_t required_num_args; zend_uchar _type_hint; zend_bool return_reference; zend_bool _allow_null; @@ -330,7 +337,7 @@ typedef struct _zend_internal_function { zend_function *prototype; uint32_t num_args; uint32_t required_num_args; - zend_arg_info *arg_info; + zend_internal_arg_info *arg_info; /* END of common elements */ void (*handler)(INTERNAL_FUNCTION_PARAMETERS); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index e848e59decd64..a9fadd10da0c6 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -525,12 +525,12 @@ static inline zval* make_real_object(zval *object_ptr TSRMLS_DC) return object; } -ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC) +ZEND_API char * zend_verify_internal_arg_class_kind(const zend_internal_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC) { zend_string *key; ALLOCA_FLAG(use_heap); - STR_ALLOCA_INIT(key, cur_arg_info->class_name, cur_arg_info->class_name_len, use_heap); + STR_ALLOCA_INIT(key, cur_arg_info->class_name, strlen(cur_arg_info->class_name), use_heap); *pce = zend_fetch_class(key, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD) TSRMLS_CC); STR_ALLOCA_FREE(key, use_heap); @@ -542,6 +542,18 @@ ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ch } } +ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC) +{ + *pce = zend_fetch_class(cur_arg_info->class_name, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD) TSRMLS_CC); + + *class_name = (*pce) ? (*pce)->name->val : cur_arg_info->class_name->val; + if (*pce && (*pce)->ce_flags & ZEND_ACC_INTERFACE) { + return "implement interface "; + } else { + return "be an instance of "; + } +} + ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC) { zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data; @@ -593,6 +605,55 @@ static int is_null_constant(zval *default_value TSRMLS_DC) return 0; } +static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg TSRMLS_DC) +{ + zend_internal_arg_info *cur_arg_info; + char *need_msg; + zend_class_entry *ce; + + if (UNEXPECTED(!zf->internal_function.arg_info)) { + return; + } + + if (EXPECTED(arg_num <= zf->internal_function.num_args)) { + cur_arg_info = &zf->internal_function.arg_info[arg_num-1]; + } else if (zf->internal_function.fn_flags & ZEND_ACC_VARIADIC) { + cur_arg_info = &zf->internal_function.arg_info[zf->internal_function.num_args-1]; + } else { + return; + } + + if (cur_arg_info->class_name) { + char *class_name; + + ZVAL_DEREF(arg); + if (Z_TYPE_P(arg) == IS_OBJECT) { + need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce TSRMLS_CC); + if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) { + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg TSRMLS_CC); + } + } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) { + need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg TSRMLS_CC); + } + } else if (cur_arg_info->type_hint) { + if (cur_arg_info->type_hint == IS_ARRAY) { + ZVAL_DEREF(arg); + if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg TSRMLS_CC); + } + } else if (cur_arg_info->type_hint == IS_CALLABLE) { + if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg TSRMLS_CC); + } +#if ZEND_DEBUG + } else { + zend_error(E_ERROR, "Unknown typehint"); +#endif + } + } +} + static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value TSRMLS_DC) { zend_arg_info *cur_arg_info; diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index ddd736c07e476..d4a46db043878 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -48,6 +48,7 @@ ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); ZEND_API int zend_eval_stringl_ex(char *str, size_t str_len, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); +ZEND_API char * zend_verify_internal_arg_class_kind(const zend_internal_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC); ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC); ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC); diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 43ef22074faf7..407acade0ef68 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -283,25 +283,40 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c if (fe_arg_info->class_name) { zend_string *fe_class_name, *proto_class_name; + const char *class_name; - if (!strcasecmp(fe_arg_info->class_name, "parent") && proto->common.scope) { + if (fe->type == ZEND_INTERNAL_FUNCTION) { + fe_class_name = NULL; + class_name = ((zend_internal_arg_info*)fe_arg_info)->class_name; + } else { + fe_class_name = fe_arg_info->class_name; + class_name = fe_arg_info->class_name->val; + } + if (!strcasecmp(class_name, "parent") && proto->common.scope) { fe_class_name = zend_string_copy(proto->common.scope->name); - } else if (!strcasecmp(fe_arg_info->class_name, "self") && fe->common.scope) { + } else if (!strcasecmp(class_name, "self") && fe->common.scope) { fe_class_name = zend_string_copy(fe->common.scope->name); + } else if (fe_class_name) { + zend_string_addref(fe_class_name); } else { - fe_class_name = zend_string_init( - fe_arg_info->class_name, - fe_arg_info->class_name_len, 0); + fe_class_name = zend_string_init(class_name, strlen(class_name), 0); } - if (!strcasecmp(proto_arg_info->class_name, "parent") && proto->common.scope && proto->common.scope->parent) { + if (proto->type == ZEND_INTERNAL_FUNCTION) { + proto_class_name = NULL; + class_name = ((zend_internal_arg_info*)proto_arg_info)->class_name; + } else { + proto_class_name = proto_arg_info->class_name; + class_name = proto_arg_info->class_name->val; + } + if (!strcasecmp(class_name, "parent") && proto->common.scope && proto->common.scope->parent) { proto_class_name = zend_string_copy(proto->common.scope->parent->name); - } else if (!strcasecmp(proto_arg_info->class_name, "self") && proto->common.scope) { + } else if (!strcasecmp(class_name, "self") && proto->common.scope) { proto_class_name = zend_string_copy(proto->common.scope->name); + } else if (proto_class_name) { + zend_string_addref(proto_class_name); } else { - proto_class_name = zend_string_init( - proto_arg_info->class_name, - proto_arg_info->class_name_len, 0); + proto_class_name = zend_string_init(class_name, strlen(class_name), 0); } if (strcasecmp(fe_class_name->val, proto_class_name->val)!=0) { @@ -373,15 +388,21 @@ static zend_string *zend_get_function_declaration(zend_function *fptr TSRMLS_DC) if (arg_info->class_name) { const char *class_name; size_t class_name_len; - if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope) { + + if (fptr->type == ZEND_INTERNAL_FUNCTION) { + class_name = ((zend_internal_arg_info*)arg_info)->class_name; + class_name_len = strlen(class_name); + } else { + class_name = arg_info->class_name->val; + class_name_len = arg_info->class_name->len; + } + + if (!strcasecmp(class_name, "self") && fptr->common.scope) { class_name = fptr->common.scope->name->val; class_name_len = fptr->common.scope->name->len; - } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) { + } else if (!strcasecmp(class_name, "parent") && fptr->common.scope->parent) { class_name = fptr->common.scope->parent->name->val; class_name_len = fptr->common.scope->parent->name->len; - } else { - class_name = arg_info->class_name; - class_name_len = arg_info->class_name_len; } smart_str_appendl(&str, class_name, class_name_len); @@ -403,7 +424,11 @@ static zend_string *zend_get_function_declaration(zend_function *fptr TSRMLS_DC) smart_str_appendc(&str, '$'); if (arg_info->name) { - smart_str_appendl(&str, arg_info->name, arg_info->name_len); + if (fptr->type == ZEND_INTERNAL_FUNCTION) { + smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->name); + } else { + smart_str_appendl(&str, arg_info->name->val, arg_info->name->len); + } } else { smart_str_appends(&str, "param"); smart_str_append_unsigned(&str, i); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 59e62149f2cd1..0ab110b52c710 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -370,9 +370,9 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC) } if (op_array->arg_info) { for (i=0; inum_args; i++) { - efree((char*)op_array->arg_info[i].name); + zend_string_release(op_array->arg_info[i].name); if (op_array->arg_info[i].class_name) { - efree((char*)op_array->arg_info[i].class_name); + zend_string_release(op_array->arg_info[i].class_name); } } efree(op_array->arg_info); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index cb9b7c120e43b..8b622c78e56ea 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2666,7 +2666,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) zval *p = ZEND_CALL_ARG(call, 1); for (i = 0; i < ZEND_CALL_NUM_ARGS(call); ++i) { - zend_verify_arg_type(fbc, i + 1, p, NULL TSRMLS_CC); + zend_verify_internal_arg_type(fbc, i + 1, p TSRMLS_CC); p++; } if (UNEXPECTED(EG(exception) != NULL)) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index f43fc32e5d080..cbf1d4b0bdf4d 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -538,7 +538,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *p = ZEND_CALL_ARG(call, 1); for (i = 0; i < ZEND_CALL_NUM_ARGS(call); ++i) { - zend_verify_arg_type(fbc, i + 1, p, NULL TSRMLS_CC); + zend_verify_internal_arg_type(fbc, i + 1, p TSRMLS_CC); p++; } if (UNEXPECTED(EG(exception) != NULL)) { diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 3e91740a71341..f6ade86acf056 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -419,12 +419,10 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc zend_accel_store(op_array->arg_info, sizeof(zend_arg_info) * op_array->num_args); for (i = 0; i < op_array->num_args; i++) { if (op_array->arg_info[i].name) { -//??? zend_accel_store_interned_string(op_array->arg_info[i].name, op_array->arg_info[i].name_len + 1); - zend_accel_store(op_array->arg_info[i].name, op_array->arg_info[i].name_len + 1); + zend_accel_store_interned_string(op_array->arg_info[i].name); } if (op_array->arg_info[i].class_name) { -//??? zend_accel_store_interned_string(op_array->arg_info[i].class_name, op_array->arg_info[i].class_name_len + 1); - zend_accel_store(op_array->arg_info[i].class_name, op_array->arg_info[i].class_name_len + 1); + zend_accel_store_interned_string(op_array->arg_info[i].class_name); } } } diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 0a7b8356487ca..6a35c5ca9bb0e 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -199,12 +199,10 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array TSRMLS_DC) ADD_DUP_SIZE(op_array->arg_info, sizeof(zend_arg_info) * op_array->num_args); for (i = 0; i < op_array->num_args; i++) { if (op_array->arg_info[i].name) { -//??? ADD_INTERNED_STRING(op_array->arg_info[i].name, op_array->arg_info[i].name_len + 1); - ADD_SIZE(op_array->arg_info[i].name_len + 1); + ADD_INTERNED_STRING(op_array->arg_info[i].name, 1); } if (op_array->arg_info[i].class_name) { -//??? ADD_INTERNED_STRING(op_array->arg_info[i].class_name, op_array->arg_info[i].class_name_len + 1); - ADD_SIZE(op_array->arg_info[i].class_name_len + 1); + ADD_INTERNED_STRING(op_array->arg_info[i].class_name, 1); } } diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 8e35c1ee9ad06..571e08b4c096c 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -1300,7 +1300,7 @@ int pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind TSRMLS_DC) if (funcs->arg_info) { zend_internal_function_info *info = (zend_internal_function_info*)funcs->arg_info; - ifunc->arg_info = (zend_arg_info*)funcs->arg_info + 1; + ifunc->arg_info = (zend_internal_arg_info*)funcs->arg_info + 1; ifunc->num_args = funcs->num_args; if (info->required_num_args == -1) { ifunc->required_num_args = funcs->num_args; diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index e9c59ea86e935..7d8f2b43ea301 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -688,7 +688,10 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg string_printf(str, " "); } if (arg_info->class_name) { - string_printf(str, "%s ", arg_info->class_name); + string_printf(str, "%s ", + (fptr->type == ZEND_INTERNAL_FUNCTION) ? + ((zend_internal_arg_info*)arg_info)->class_name : + arg_info->class_name->val); if (arg_info->allow_null) { string_printf(str, "or NULL "); } @@ -705,7 +708,10 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg string_write(str, "...", sizeof("...")-1); } if (arg_info->name) { - string_printf(str, "$%s", arg_info->name); + string_printf(str, "$%s", + (fptr->type == ZEND_INTERNAL_FUNCTION) ? + ((zend_internal_arg_info*)arg_info)->name : + arg_info->name->val); } else { string_printf(str, "$param%d", offset); } @@ -1226,7 +1232,11 @@ static void reflection_parameter_factory(zend_function *fptr, zval *closure_obje zval name; if (arg_info->name) { - ZVAL_STRINGL(&name, arg_info->name, arg_info->name_len); + if (fptr->type == ZEND_INTERNAL_FUNCTION) { + ZVAL_STRING(&name, ((zend_internal_arg_info*)arg_info)->name); + } else { + ZVAL_STR(&name, zend_string_copy(arg_info->name)); + } } else { ZVAL_NULL(&name); } @@ -2127,6 +2137,7 @@ ZEND_METHOD(reflection_parameter, __construct) int position; zend_class_entry *ce = NULL; zend_bool is_closure = 0; + zend_bool is_invoke = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &reference, ¶meter) == FAILURE) { return; @@ -2188,9 +2199,10 @@ ZEND_METHOD(reflection_parameter, __construct) && (lcname_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 && (fptr = zend_get_closure_invoke_method(Z_OBJ_P(classref) TSRMLS_CC)) != NULL) - { + { /* nothing to do. don't set is_closure since is the invoke handler, -- not the closure itself */ + 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 TSRMLS_CC, @@ -2243,10 +2255,24 @@ ZEND_METHOD(reflection_parameter, __construct) position= -1; convert_to_string_ex(parameter); - for (i = 0; i < fptr->common.num_args; i++) { - if (arg_info[i].name && strcmp(arg_info[i].name, Z_STRVAL_P(parameter)) == 0) { - position= i; - break; + if (!is_invoke && fptr->type == ZEND_INTERNAL_FUNCTION) { + for (i = 0; i < fptr->common.num_args; i++) { + if (arg_info[i].name) { + if (strcmp(((zend_internal_arg_info*)arg_info)[i].name, Z_STRVAL_P(parameter)) == 0) { + position= i; + break; + } + + } + } + } else { + for (i = 0; i < fptr->common.num_args; i++) { + if (arg_info[i].name) { + if (strcmp(arg_info[i].name->val, Z_STRVAL_P(parameter)) == 0) { + position= i; + break; + } + } } } if (position == -1) { @@ -2265,7 +2291,11 @@ ZEND_METHOD(reflection_parameter, __construct) } if (arg_info[position].name) { - ZVAL_STRINGL(&name, arg_info[position].name, arg_info[position].name_len); + if (fptr->type == ZEND_INTERNAL_FUNCTION) { + ZVAL_STRING(&name, ((zend_internal_arg_info*)arg_info)[position].name); + } else { + ZVAL_STR(&name, zend_string_copy(arg_info[position].name)); + } } else { ZVAL_NULL(&name); } @@ -2379,14 +2409,24 @@ ZEND_METHOD(reflection_parameter, getClass) * TODO: Think about moving these checks to the compiler or some sort of * lint-mode. */ - if (0 == zend_binary_strcasecmp(param->arg_info->class_name, param->arg_info->class_name_len, "self", sizeof("self")- 1)) { + const char *class_name; + size_t class_name_len; + + if (param->fptr->type == ZEND_INTERNAL_FUNCTION) { + class_name = ((zend_internal_arg_info*)param->arg_info)->class_name; + class_name_len = strlen(class_name); + } else { + class_name = param->arg_info->class_name->val; + class_name_len = param->arg_info->class_name->len; + } + if (0 == zend_binary_strcasecmp(class_name, class_name_len, "self", sizeof("self")- 1)) { ce = param->fptr->common.scope; if (!ce) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter uses 'self' as type hint but function is not a class member!"); return; } - } else if (0 == zend_binary_strcasecmp(param->arg_info->class_name, param->arg_info->class_name_len, "parent", sizeof("parent")- 1)) { + } else if (0 == zend_binary_strcasecmp(class_name, class_name_len, "parent", sizeof("parent")- 1)) { ce = param->fptr->common.scope; if (!ce) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, @@ -2400,12 +2440,16 @@ ZEND_METHOD(reflection_parameter, getClass) } ce = ce->parent; } else { - zend_string *name = zend_string_init(param->arg_info->class_name, param->arg_info->class_name_len, 0); - ce = zend_lookup_class(name TSRMLS_CC); - zend_string_release(name); + if (param->fptr->type == ZEND_INTERNAL_FUNCTION) { + zend_string *name = zend_string_init(class_name, class_name_len, 0); + ce = zend_lookup_class(name TSRMLS_CC); + zend_string_release(name); + } else { + ce = zend_lookup_class(param->arg_info->class_name TSRMLS_CC); + } if (!ce) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Class %s does not exist", param->arg_info->class_name); + "Class %s does not exist", class_name); return; } } @@ -3347,9 +3391,8 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value zend_property_info *prop_info; zval *prop, prop_copy; zend_string *key; - zend_ulong num_index; - ZEND_HASH_FOREACH_KEY_PTR(&ce->properties_info, num_index, key, prop_info) { + ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) { if (((prop_info->flags & ZEND_ACC_SHADOW) && prop_info->ce != ce) || ((prop_info->flags & ZEND_ACC_PROTECTED) &&