summaryrefslogtreecommitdiff
path: root/Zend/zend_API.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_API.c')
-rw-r--r--Zend/zend_API.c273
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
*/