diff options
Diffstat (limited to 'Zend/zend_API.c')
-rw-r--r-- | Zend/zend_API.c | 273 |
1 files changed, 181 insertions, 92 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 604dd47c70..fedef6f574 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -202,13 +202,43 @@ ZEND_API char *zend_zval_type_name(const zval *arg) /* {{{ */ } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_count_error(int num_args, int min_num_args, int max_num_args) /* {{{ */ +ZEND_API zend_string *zend_zval_get_type(const zval *arg) /* {{{ */ +{ + switch (Z_TYPE_P(arg)) { + case IS_NULL: + return ZSTR_KNOWN(ZEND_STR_NULL); + case IS_FALSE: + case IS_TRUE: + return ZSTR_KNOWN(ZEND_STR_BOOLEAN); + case IS_LONG: + return ZSTR_KNOWN(ZEND_STR_INTEGER); + case IS_DOUBLE: + return ZSTR_KNOWN(ZEND_STR_DOUBLE); + case IS_STRING: + return ZSTR_KNOWN(ZEND_STR_STRING); + case IS_ARRAY: + return ZSTR_KNOWN(ZEND_STR_ARRAY); + case IS_OBJECT: + return ZSTR_KNOWN(ZEND_STR_OBJECT); + case IS_RESOURCE: + if (zend_rsrc_list_get_rsrc_type(Z_RES_P(arg))) { + return ZSTR_KNOWN(ZEND_STR_RESOURCE); + } else { + return ZSTR_KNOWN(ZEND_STR_CLOSED_RESOURCE); + } + default: + return NULL; + } +} +/* }}} */ + +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_count_error(zend_bool throw_, int num_args, int min_num_args, int max_num_args) /* {{{ */ { zend_function *active_function = EG(current_execute_data)->func; const char *class_name = active_function->common.scope ? ZSTR_VAL(active_function->common.scope->name) : ""; zend_internal_argument_count_error( - ZEND_ARG_USES_STRICT_TYPES(), + throw_ || ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects %s %d parameter%s, %d given", class_name, \ class_name[0] ? "::" : "", \ @@ -220,7 +250,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_count_error(int num_ } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(int num, zend_expected_type expected_type, zval *arg) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(zend_bool throw_, int num, zend_expected_type expected_type, zval *arg) /* {{{ */ { const char *space; const char *class_name = get_active_class_name(&space); @@ -229,28 +259,28 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(int num, z NULL }; - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be %s, %s given", + zend_internal_type_error(throw_ || ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be %s, %s given", class_name, space, get_active_function_name(), num, expected_error[expected_type], zend_zval_type_name(arg)); } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_error(int num, char *name, zval *arg) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_error(zend_bool throw_, int num, char *name, zval *arg) /* {{{ */ { const char *space; const char *class_name = get_active_class_name(&space); - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be %s, %s given", + zend_internal_type_error(throw_ || ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be %s, %s given", class_name, space, get_active_function_name(), num, name, zend_zval_type_name(arg)); } /* }}} */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(int severity, int num, char *error) /* {{{ */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(zend_bool throw_, int severity, int num, char *error) /* {{{ */ { const char *space; const char *class_name = get_active_class_name(&space); if (severity == E_WARNING) { - zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be a valid callback, %s", + zend_internal_type_error(throw_ || ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be a valid callback, %s", class_name, space, get_active_function_name(), num, error); } else if (severity == E_ERROR) { zend_throw_error(zend_ce_type_error, "%s%s%s() expects parameter %d to be a valid callback, %s", @@ -1377,7 +1407,7 @@ ZEND_API int add_assoc_str_ex(zval *arg, const char *key, size_t key_len, zend_s } /* }}} */ -ZEND_API int add_assoc_string_ex(zval *arg, const char *key, size_t key_len, char *str) /* {{{ */ +ZEND_API int add_assoc_string_ex(zval *arg, const char *key, size_t key_len, const char *str) /* {{{ */ { zval *ret, tmp; @@ -1387,7 +1417,7 @@ ZEND_API int add_assoc_string_ex(zval *arg, const char *key, size_t key_len, cha } /* }}} */ -ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, size_t key_len, char *str, size_t length) /* {{{ */ +ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length) /* {{{ */ { zval *ret, tmp; @@ -1562,7 +1592,7 @@ ZEND_API int add_next_index_zval(zval *arg, zval *value) /* {{{ */ } /* }}} */ -ZEND_API zval *add_get_assoc_string_ex(zval *arg, const char *key, uint key_len, const char *str) /* {{{ */ +ZEND_API zval *add_get_assoc_string_ex(zval *arg, const char *key, uint32_t key_len, const char *str) /* {{{ */ { zval tmp, *ret; @@ -1572,7 +1602,7 @@ ZEND_API zval *add_get_assoc_string_ex(zval *arg, const char *key, uint key_len, } /* }}} */ -ZEND_API zval *add_get_assoc_stringl_ex(zval *arg, const char *key, uint key_len, const char *str, size_t length) /* {{{ */ +ZEND_API zval *add_get_assoc_stringl_ex(zval *arg, const char *key, uint32_t key_len, const char *str, size_t length) /* {{{ */ { zval tmp, *ret; @@ -2019,6 +2049,7 @@ ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module) / lcname = zend_string_alloc(name_len, 1); zend_str_tolower_copy(ZSTR_VAL(lcname), module->name, name_len); + lcname = zend_new_interned_string(lcname); if ((module_ptr = zend_hash_add_mem(&module_registry, lcname, module, sizeof(zend_module_entry))) == NULL) { zend_error(E_CORE_WARNING, "Module '%s' already loaded", module->name); zend_string_release(lcname); @@ -2189,11 +2220,15 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio /* Don't count the variadic argument */ internal_function->num_args--; } - if (info->type_hint) { - if (info->class_name) { - ZEND_ASSERT(info->type_hint == IS_OBJECT); - if (!scope && (!strcasecmp(info->class_name, "self") || !strcasecmp(info->class_name, "parent"))) { - zend_error_noreturn(E_CORE_ERROR, "Cannot declare a return type of %s outside of a class scope", info->class_name); + if (ZEND_TYPE_IS_SET(info->type)) { + if (ZEND_TYPE_IS_CLASS(info->type)) { + const char *type_name = (const char*)info->type; + + if (type_name[0] == '?') { + type_name++; + } + if (!scope && (!strcasecmp(type_name, "self") || !strcasecmp(type_name, "parent"))) { + zend_error_noreturn(E_CORE_ERROR, "Cannot declare a return type of %s outside of a class scope", type_name); } } @@ -2250,14 +2285,43 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio if (reg_function->common.arg_info && reg_function->common.num_args) { uint32_t i; for (i = 0; i < reg_function->common.num_args; i++) { - if (reg_function->common.arg_info[i].class_name || - reg_function->common.arg_info[i].type_hint) { + if (ZEND_TYPE_IS_SET(reg_function->common.arg_info[i].type)) { reg_function->common.fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; break; } } } + if (reg_function->common.arg_info && + (reg_function->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) { + /* convert "const char*" class type names into "zend_string*" */ + uint32_t i; + uint32_t num_args = reg_function->common.num_args + 1; + zend_arg_info *arg_info = reg_function->common.arg_info - 1; + zend_arg_info *new_arg_info; + + if (reg_function->common.fn_flags & ZEND_ACC_VARIADIC) { + num_args++; + } + new_arg_info = malloc(sizeof(zend_arg_info) * num_args); + memcpy(new_arg_info, arg_info, sizeof(zend_arg_info) * num_args); + reg_function->common.arg_info = new_arg_info + 1; + for (i = 0; i < num_args; i++) { + if (ZEND_TYPE_IS_CLASS(new_arg_info[i].type)) { + const char *class_name = (const char*)new_arg_info[i].type; + zend_bool allow_null = 0; + zend_string *str; + + if (class_name[0] == '?') { + class_name++; + allow_null = 1; + } + str = zend_new_interned_string(zend_string_init(class_name, strlen(class_name), 1)); + new_arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(str, allow_null); + } + } + } + if (scope) { /* Look for ctor, dtor, clone * If it's an old-style constructor, store it only if we don't have @@ -2349,7 +2413,6 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio dtor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC; } if (clone) { - clone->common.fn_flags |= ZEND_ACC_CLONE; if (clone->common.fn_flags & ZEND_ACC_STATIC) { zend_error(error_type, "%s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(clone->common.function_name)); } @@ -2520,12 +2583,10 @@ void module_destructor(zend_module_entry *module) /* {{{ */ } #if HAVE_LIBDL -#if !(defined(NETWARE) && defined(APACHE_1_BUILD)) if (module->handle && !getenv("ZEND_DONT_UNLOAD_MODULES")) { DL_UNLOAD(module->handle); } #endif -#endif } /* }}} */ @@ -2724,6 +2785,7 @@ ZEND_API int zend_register_class_alias_ex(const char *name, size_t name_len, zen zend_assert_valid_class_name(lcname); + lcname = zend_new_interned_string(lcname); ce = zend_hash_add_ptr(CG(class_table), lcname, ce); zend_string_release(lcname); if (ce) { @@ -3184,14 +3246,86 @@ get_function_via_handler: } /* }}} */ -ZEND_API zend_bool zend_is_callable_ex(zval *callable, zend_object *object, uint check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error) /* {{{ */ +static zend_string *zend_create_method_string(zend_string *class_name, zend_string *method_name) { + zend_string *callable_name = zend_string_alloc( + ZSTR_LEN(class_name) + ZSTR_LEN(method_name) + sizeof("::") - 1, 0); + char *ptr = ZSTR_VAL(callable_name); + memcpy(ptr, ZSTR_VAL(class_name), ZSTR_LEN(class_name)); + ptr += ZSTR_LEN(class_name); + memcpy(ptr, "::", sizeof("::") - 1); + ptr += sizeof("::") - 1; + memcpy(ptr, ZSTR_VAL(method_name), ZSTR_LEN(method_name) + 1); + return callable_name; +} + +ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, zend_object *object) /* {{{ */ +{ +try_again: + switch (Z_TYPE_P(callable)) { + case IS_STRING: + if (object) { + return zend_create_method_string(object->ce->name, Z_STR_P(callable)); + } + return zend_string_copy(Z_STR_P(callable)); + + case IS_ARRAY: + { + zval *method = NULL; + zval *obj = NULL; + + if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) { + obj = zend_hash_index_find_deref(Z_ARRVAL_P(callable), 0); + method = zend_hash_index_find_deref(Z_ARRVAL_P(callable), 1); + } + + if (obj == NULL || method == NULL || Z_TYPE_P(method) != IS_STRING) { + return zend_string_init("Array", sizeof("Array")-1, 0); + } + + if (Z_TYPE_P(obj) == IS_STRING) { + return zend_create_method_string(Z_STR_P(obj), Z_STR_P(method)); + } else if (Z_TYPE_P(obj) == IS_OBJECT) { + return zend_create_method_string(Z_OBJCE_P(obj)->name, Z_STR_P(method)); + } else { + return zend_string_init("Array", sizeof("Array")-1, 0); + } + } + case IS_OBJECT: + { + zend_class_entry *calling_scope; + zend_function *fptr; + zend_object *object; + if (Z_OBJ_HANDLER_P(callable, get_closure) + && Z_OBJ_HANDLER_P(callable, get_closure)(callable, &calling_scope, &fptr, &object) == SUCCESS) { + zend_class_entry *ce = Z_OBJCE_P(callable); + zend_string *callable_name = zend_string_alloc( + ZSTR_LEN(ce->name) + sizeof("::__invoke") - 1, 0); + memcpy(ZSTR_VAL(callable_name), ZSTR_VAL(ce->name), ZSTR_LEN(ce->name)); + memcpy(ZSTR_VAL(callable_name) + ZSTR_LEN(ce->name), "::__invoke", sizeof("::__invoke")); + return callable_name; + } + return zval_get_string(callable); + } + case IS_REFERENCE: + callable = Z_REFVAL_P(callable); + goto try_again; + default: + return zval_get_string(callable); + } +} +/* }}} */ + +ZEND_API zend_string *zend_get_callable_name(zval *callable) /* {{{ */ +{ + return zend_get_callable_name_ex(callable, NULL); +} +/* }}} */ + +static zend_bool zend_is_callable_impl(zval *callable, zend_object *object, uint32_t check_flags, zend_fcall_info_cache *fcc, char **error) /* {{{ */ { zend_bool ret; zend_fcall_info_cache fcc_local; - if (callable_name) { - *callable_name = NULL; - } if (fcc == NULL) { fcc = &fcc_local; } @@ -3205,32 +3339,14 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, zend_object *object, uint fcc->function_handler = NULL; fcc->object = NULL; - if (object && - (!EG(objects_store).object_buckets || - !IS_OBJ_VALID(EG(objects_store).object_buckets[object->handle]))) { - return 0; - } - again: switch (Z_TYPE_P(callable)) { case IS_STRING: if (object) { fcc->object = object; fcc->calling_scope = object->ce; - if (callable_name) { - char *ptr; - - *callable_name = zend_string_alloc(ZSTR_LEN(fcc->calling_scope->name) + Z_STRLEN_P(callable) + sizeof("::") - 1, 0); - ptr = ZSTR_VAL(*callable_name); - memcpy(ptr, ZSTR_VAL(fcc->calling_scope->name), ZSTR_LEN(fcc->calling_scope->name)); - ptr += ZSTR_LEN(fcc->calling_scope->name); - memcpy(ptr, "::", sizeof("::") - 1); - ptr += sizeof("::") - 1; - memcpy(ptr, Z_STRVAL_P(callable), Z_STRLEN_P(callable) + 1); - } - } else if (callable_name) { - *callable_name = zend_string_copy(Z_STR_P(callable)); } + if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) { fcc->called_scope = fcc->calling_scope; return 1; @@ -3273,19 +3389,6 @@ again: ZVAL_DEREF(obj); if (Z_TYPE_P(obj) == IS_STRING) { - if (callable_name) { - char *ptr; - - - *callable_name = zend_string_alloc(Z_STRLEN_P(obj) + Z_STRLEN_P(method) + sizeof("::") - 1, 0); - ptr = ZSTR_VAL(*callable_name); - memcpy(ptr, Z_STRVAL_P(obj), Z_STRLEN_P(obj)); - ptr += Z_STRLEN_P(obj); - memcpy(ptr, "::", sizeof("::") - 1); - ptr += sizeof("::") - 1; - memcpy(ptr, Z_STRVAL_P(method), Z_STRLEN_P(method) + 1); - } - if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) { return 1; } @@ -3295,27 +3398,11 @@ again: } } else if (Z_TYPE_P(obj) == IS_OBJECT) { - if (!EG(objects_store).object_buckets || - !IS_OBJ_VALID(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(obj)])) { - return 0; - } fcc->calling_scope = Z_OBJCE_P(obj); /* TBFixed: what if it's overloaded? */ fcc->object = Z_OBJ_P(obj); - if (callable_name) { - char *ptr; - - *callable_name = zend_string_alloc(ZSTR_LEN(fcc->calling_scope->name) + Z_STRLEN_P(method) + sizeof("::") - 1, 0); - ptr = ZSTR_VAL(*callable_name); - memcpy(ptr, ZSTR_VAL(fcc->calling_scope->name), ZSTR_LEN(fcc->calling_scope->name)); - ptr += ZSTR_LEN(fcc->calling_scope->name); - memcpy(ptr, "::", sizeof("::") - 1); - ptr += sizeof("::") - 1; - memcpy(ptr, Z_STRVAL_P(method), Z_STRLEN_P(method) + 1); - } - if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) { fcc->called_scope = fcc->calling_scope; return 1; @@ -3350,43 +3437,36 @@ again: } else { if (error) zend_spprintf(error, 0, "array must have exactly two members"); } - if (callable_name) { - *callable_name = zend_string_init("Array", sizeof("Array")-1, 0); - } } return 0; case IS_OBJECT: if (Z_OBJ_HANDLER_P(callable, get_closure) && Z_OBJ_HANDLER_P(callable, get_closure)(callable, &fcc->calling_scope, &fcc->function_handler, &fcc->object) == SUCCESS) { fcc->called_scope = fcc->calling_scope; - if (callable_name) { - zend_class_entry *ce = Z_OBJCE_P(callable); /* TBFixed: what if it's overloaded? */ - - *callable_name = zend_string_alloc(ZSTR_LEN(ce->name) + sizeof("::__invoke") - 1, 0); - memcpy(ZSTR_VAL(*callable_name), ZSTR_VAL(ce->name), ZSTR_LEN(ce->name)); - memcpy(ZSTR_VAL(*callable_name) + ZSTR_LEN(ce->name), "::__invoke", sizeof("::__invoke")); - } fcc->initialized = 1; return 1; } - if (callable_name) { - *callable_name = zval_get_string(callable); - } if (error) zend_spprintf(error, 0, "no array or string given"); return 0; case IS_REFERENCE: callable = Z_REFVAL_P(callable); goto again; default: - if (callable_name) { - *callable_name = zval_get_string(callable); - } if (error) zend_spprintf(error, 0, "no array or string given"); return 0; } } /* }}} */ -ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, zend_string **callable_name) /* {{{ */ +ZEND_API zend_bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error) /* {{{ */ +{ + zend_bool ret = zend_is_callable_impl(callable, object, check_flags, fcc, error); + if (callable_name) { + *callable_name = zend_get_callable_name_ex(callable, object); + } + return ret; +} + +ZEND_API zend_bool zend_is_callable(zval *callable, uint32_t check_flags, zend_string **callable_name) /* {{{ */ { return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL); } @@ -3418,7 +3498,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam } /* }}} */ -ZEND_API int zend_fcall_info_init(zval *callable, uint check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error) /* {{{ */ +ZEND_API int zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error) /* {{{ */ { if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, fcc, error)) { return FAILURE; @@ -3666,7 +3746,11 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z default: break; } + + /* Must be interned to avoid ZTS data races */ + name = zend_new_interned_string(zend_string_copy(name)); } + if (access_type & ZEND_ACC_PUBLIC) { property_info->name = zend_string_copy(name); } else if (access_type & ZEND_ACC_PRIVATE) { @@ -3791,6 +3875,9 @@ ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, int ret; zend_string *key = zend_string_init(name, name_length, ce->type & ZEND_INTERNAL_CLASS); + if (ce->type == ZEND_INTERNAL_CLASS) { + key = zend_new_interned_string(key); + } ret = zend_declare_class_constant_ex(ce, key, value, ZEND_ACC_PUBLIC, NULL); zend_string_release(key); return ret; @@ -4250,4 +4337,6 @@ ZEND_API zend_bool zend_is_iterable(zval *iterable) /* {{{ */ * c-basic-offset: 4 * indent-tabs-mode: t * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 */ |