diff options
Diffstat (limited to 'Zend/zend_API.c')
-rw-r--r-- | Zend/zend_API.c | 596 |
1 files changed, 328 insertions, 268 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 3d94fd5986..a56231e7c8 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | Zend Engine | +----------------------------------------------------------------------+ - | Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) | + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | | that is bundled with this package in the file LICENSE, and is | @@ -30,9 +30,7 @@ #include "zend_closures.h" #include "zend_inheritance.h" -#ifdef HAVE_STDARG_H #include <stdarg.h> -#endif /* these variables are true statics/globals, and have to be mutex'ed on every access */ ZEND_API HashTable module_registry; @@ -1174,9 +1172,22 @@ ZEND_API int zend_update_class_constants(zend_class_entry *class_type) /* {{{ */ } else { val = (zval*)((char*)class_type->default_properties_table + prop_info->offset - OBJ_PROP_TO_OFFSET(0)); } - ZVAL_DEREF(val); if (Z_TYPE_P(val) == IS_CONSTANT_AST) { - if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) { + if (prop_info->type) { + zval tmp; + + ZVAL_COPY(&tmp, val); + if (UNEXPECTED(zval_update_constant_ex(&tmp, ce) != SUCCESS)) { + return FAILURE; + } + /* property initializers must always be evaluated with strict types */; + if (UNEXPECTED(!zend_verify_property_type(prop_info, &tmp, /* strict */ 1))) { + zval_ptr_dtor(&tmp); + return FAILURE; + } + zval_ptr_dtor(val); + ZVAL_COPY_VALUE(val, &tmp); + } else if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) { return FAILURE; } } @@ -1192,7 +1203,7 @@ ZEND_API int zend_update_class_constants(zend_class_entry *class_type) /* {{{ */ } /* }}} */ -ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type) /* {{{ */ +static zend_always_inline void _object_properties_init(zend_object *object, zend_class_entry *class_type) /* {{{ */ { if (class_type->default_properties_count) { zval *src = class_type->default_properties_table; @@ -1212,11 +1223,17 @@ ZEND_API void object_properties_init(zend_object *object, zend_class_entry *clas dst++; } while (src != end); } - object->properties = NULL; } } /* }}} */ +ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type) /* {{{ */ +{ + object->properties = NULL; + _object_properties_init(object, class_type); +} +/* }}} */ + ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properties) /* {{{ */ { object->properties = properties; @@ -1231,7 +1248,18 @@ ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properti property_info && (property_info->flags & ZEND_ACC_STATIC) == 0) { zval *slot = OBJ_PROP(object, property_info->offset); - ZVAL_COPY_VALUE(slot, prop); + + if (UNEXPECTED(property_info->type)) { + zval tmp; + + ZVAL_COPY_VALUE(&tmp, prop); + if (UNEXPECTED(!zend_verify_property_type(property_info, &tmp, 0))) { + continue; + } + ZVAL_COPY_VALUE(slot, &tmp); + } else { + ZVAL_COPY_VALUE(slot, prop); + } ZVAL_INDIRECT(prop, slot); } } ZEND_HASH_FOREACH_END(); @@ -1301,7 +1329,7 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) * class and all props being public. If only a subset is given or the class * has protected members then you need to merge the properties separately by * calling zend_merge_properties(). */ -ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties) /* {{{ */ +static zend_always_inline int _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties) /* {{{ */ { if (UNEXPECTED(class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) { if (class_type->ce_flags & ZEND_ACC_INTERFACE) { @@ -1325,11 +1353,13 @@ ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *class_type, } if (class_type->create_object == NULL) { - ZVAL_OBJ(arg, zend_objects_new(class_type)); + zend_object *obj = zend_objects_new(class_type); + + ZVAL_OBJ(arg, obj); if (properties) { - object_properties_init_ex(Z_OBJ_P(arg), properties); + object_properties_init_ex(obj, properties); } else { - object_properties_init(Z_OBJ_P(arg), class_type); + _object_properties_init(obj, class_type); } } else { ZVAL_OBJ(arg, class_type->create_object(class_type)); @@ -1338,9 +1368,15 @@ ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *class_type, } /* }}} */ +ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties) /* {{{ */ +{ + return _object_and_properties_init(arg, class_type, properties); +} +/* }}} */ + ZEND_API int object_init_ex(zval *arg, zend_class_entry *class_type) /* {{{ */ { - return object_and_properties_init(arg, class_type, 0); + return _object_and_properties_init(arg, class_type, NULL); } /* }}} */ @@ -1518,13 +1554,6 @@ ZEND_API int add_index_stringl(zval *arg, zend_ulong index, const char *str, siz } /* }}} */ -ZEND_API int add_index_zval(zval *arg, zend_ulong index, zval *value) /* {{{ */ -{ - zend_hash_index_update(Z_ARRVAL_P(arg), index, value); - return SUCCESS; -} -/* }}} */ - ZEND_API int add_next_index_long(zval *arg, zend_long n) /* {{{ */ { zval tmp; @@ -1597,77 +1626,6 @@ ZEND_API int add_next_index_stringl(zval *arg, const char *str, size_t length) / } /* }}} */ -ZEND_API int add_next_index_zval(zval *arg, zval *value) /* {{{ */ -{ - return zend_hash_next_index_insert(Z_ARRVAL_P(arg), value) ? SUCCESS : FAILURE; -} -/* }}} */ - -ZEND_API zval *add_get_assoc_string_ex(zval *arg, const char *key, uint32_t key_len, const char *str) /* {{{ */ -{ - zval tmp, *ret; - - ZVAL_STRING(&tmp, str); - ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp); - return ret; -} -/* }}} */ - -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; - - ZVAL_STRINGL(&tmp, str, length); - ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp); - return ret; -} -/* }}} */ - -ZEND_API zval *add_get_index_long(zval *arg, zend_ulong index, zend_long l) /* {{{ */ -{ - zval tmp; - - ZVAL_LONG(&tmp, l); - return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); -} -/* }}} */ - -ZEND_API zval *add_get_index_double(zval *arg, zend_ulong index, double d) /* {{{ */ -{ - zval tmp; - - ZVAL_DOUBLE(&tmp, d); - return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); -} -/* }}} */ - -ZEND_API zval *add_get_index_str(zval *arg, zend_ulong index, zend_string *str) /* {{{ */ -{ - zval tmp; - - ZVAL_STR(&tmp, str); - return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); -} -/* }}} */ - -ZEND_API zval *add_get_index_string(zval *arg, zend_ulong index, const char *str) /* {{{ */ -{ - zval tmp; - - ZVAL_STRING(&tmp, str); - return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); -} -/* }}} */ - -ZEND_API zval *add_get_index_stringl(zval *arg, zend_ulong index, const char *str, size_t length) /* {{{ */ -{ - zval tmp; - - ZVAL_STRINGL(&tmp, str, length); - return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp); -} -/* }}} */ - ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */ { zval *result; @@ -1712,52 +1670,37 @@ ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */ ZEND_API int add_property_long_ex(zval *arg, const char *key, size_t key_len, zend_long n) /* {{{ */ { zval tmp; - zval z_key; ZVAL_LONG(&tmp, n); - ZVAL_STRINGL(&z_key, key, key_len); - Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL); - zval_ptr_dtor(&z_key); - return SUCCESS; + return add_property_zval_ex(arg, key, key_len, &tmp); } /* }}} */ ZEND_API int add_property_bool_ex(zval *arg, const char *key, size_t key_len, zend_long b) /* {{{ */ { zval tmp; - zval z_key; ZVAL_BOOL(&tmp, b); - ZVAL_STRINGL(&z_key, key, key_len); - Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL); - zval_ptr_dtor(&z_key); - return SUCCESS; + return add_property_zval_ex(arg, key, key_len, &tmp); } /* }}} */ ZEND_API int add_property_null_ex(zval *arg, const char *key, size_t key_len) /* {{{ */ { zval tmp; - zval z_key; ZVAL_NULL(&tmp); - ZVAL_STRINGL(&z_key, key, key_len); - Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL); - zval_ptr_dtor(&z_key); - return SUCCESS; + return add_property_zval_ex(arg, key, key_len, &tmp); } /* }}} */ ZEND_API int add_property_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r) /* {{{ */ { zval tmp; - zval z_key; ZVAL_RES(&tmp, r); - ZVAL_STRINGL(&z_key, key, key_len); - Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL); + add_property_zval_ex(arg, key, key_len, &tmp); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ - zval_ptr_dtor(&z_key); return SUCCESS; } /* }}} */ @@ -1765,26 +1708,19 @@ ZEND_API int add_property_resource_ex(zval *arg, const char *key, size_t key_len ZEND_API int add_property_double_ex(zval *arg, const char *key, size_t key_len, double d) /* {{{ */ { zval tmp; - zval z_key; ZVAL_DOUBLE(&tmp, d); - ZVAL_STRINGL(&z_key, key, key_len); - Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL); - zval_ptr_dtor(&z_key); - return SUCCESS; + return add_property_zval_ex(arg, key, key_len, &tmp); } /* }}} */ ZEND_API int add_property_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str) /* {{{ */ { zval tmp; - zval z_key; ZVAL_STR(&tmp, str); - ZVAL_STRINGL(&z_key, key, key_len); - Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL); + add_property_zval_ex(arg, key, key_len, &tmp); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ - zval_ptr_dtor(&z_key); return SUCCESS; } /* }}} */ @@ -1792,13 +1728,10 @@ ZEND_API int add_property_str_ex(zval *arg, const char *key, size_t key_len, zen ZEND_API int add_property_string_ex(zval *arg, const char *key, size_t key_len, const char *str) /* {{{ */ { zval tmp; - zval z_key; ZVAL_STRING(&tmp, str); - ZVAL_STRINGL(&z_key, key, key_len); - Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL); + add_property_zval_ex(arg, key, key_len, &tmp); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ - zval_ptr_dtor(&z_key); return SUCCESS; } /* }}} */ @@ -1806,13 +1739,10 @@ ZEND_API int add_property_string_ex(zval *arg, const char *key, size_t key_len, ZEND_API int add_property_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length) /* {{{ */ { zval tmp; - zval z_key; ZVAL_STRINGL(&tmp, str, length); - ZVAL_STRINGL(&z_key, key, key_len); - Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL); + add_property_zval_ex(arg, key, key_len, &tmp); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ - zval_ptr_dtor(&z_key); return SUCCESS; } /* }}} */ @@ -2108,31 +2038,31 @@ ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, } else if (name_len == sizeof(ZEND_GET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME) - 1)) { if (fptr->common.num_args != 1) { zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ZSTR_VAL(ce->name), ZEND_GET_FUNC_NAME); - } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) { + } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) { zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_GET_FUNC_NAME); } } else if (name_len == sizeof(ZEND_SET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME) - 1)) { if (fptr->common.num_args != 2) { zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), ZEND_SET_FUNC_NAME); - } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) { + } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) { zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_SET_FUNC_NAME); } } else if (name_len == sizeof(ZEND_UNSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME) - 1)) { if (fptr->common.num_args != 1) { zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ZSTR_VAL(ce->name), ZEND_UNSET_FUNC_NAME); - } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) { + } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) { zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_UNSET_FUNC_NAME); } } else if (name_len == sizeof(ZEND_ISSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME) - 1)) { if (fptr->common.num_args != 1) { zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ZSTR_VAL(ce->name), ZEND_ISSET_FUNC_NAME); - } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) { + } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) { zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_ISSET_FUNC_NAME); } } else if (name_len == sizeof(ZEND_CALL_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME) - 1)) { if (fptr->common.num_args != 2) { zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), ZEND_CALL_FUNC_NAME); - } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) { + } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) { zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_CALL_FUNC_NAME); } } else if (name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME) - 1 && @@ -2140,7 +2070,7 @@ ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, ) { if (fptr->common.num_args != 2) { zend_error(error_type, "Method %s::__callStatic() must take exactly 2 arguments", ZSTR_VAL(ce->name)); - } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) { + } else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) { zend_error(error_type, "Method %s::__callStatic() cannot take arguments by reference", ZSTR_VAL(ce->name)); } } else if (name_len == sizeof(ZEND_TOSTRING_FUNC_NAME) - 1 && @@ -2163,7 +2093,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio int count=0, unload=0; HashTable *target_function_table = function_table; int error_type; - zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL, *__debugInfo = NULL; + zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL, *__debugInfo = NULL, *serialize_func = NULL, *unserialize_func = NULL; zend_string *lowercase_name; size_t fname_len; const char *lc_class_name = NULL; @@ -2338,6 +2268,10 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio */ if ((fname_len == class_name_len) && !ctor && !memcmp(ZSTR_VAL(lowercase_name), lc_class_name, class_name_len+1)) { ctor = reg_function; + } else if (zend_string_equals_literal(lowercase_name, "serialize")) { + serialize_func = reg_function; + } else if (zend_string_equals_literal(lowercase_name, "unserialize")) { + unserialize_func = reg_function; } else if (ZSTR_VAL(lowercase_name)[0] != '_' || ZSTR_VAL(lowercase_name)[1] != '_') { reg_function = NULL; } else if (zend_string_equals_literal(lowercase_name, ZEND_CONSTRUCTOR_FUNC_NAME)) { @@ -2409,6 +2343,8 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio scope->__unset = __unset; scope->__isset = __isset; scope->__debugInfo = __debugInfo; + scope->serialize_func = serialize_func; + scope->unserialize_func = unserialize_func; if (ctor) { ctor->common.fn_flags |= ZEND_ACC_CTOR; if (ctor->common.fn_flags & ZEND_ACC_STATIC) { @@ -2477,11 +2413,11 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio } } - if (ctor && ctor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE && ctor->common.fn_flags & ZEND_ACC_CTOR) { + if (ctor && (ctor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) { zend_error_noreturn(E_CORE_ERROR, "Constructor %s::%s() cannot declare a return type", ZSTR_VAL(scope->name), ZSTR_VAL(ctor->common.function_name)); } - if (dtor && dtor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE && dtor->common.fn_flags & ZEND_ACC_DTOR) { + if (dtor && (dtor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) { zend_error_noreturn(E_CORE_ERROR, "Destructor %s::%s() cannot declare a return type", ZSTR_VAL(scope->name), ZSTR_VAL(dtor->common.function_name)); } @@ -2617,28 +2553,22 @@ ZEND_API void zend_activate_modules(void) /* {{{ */ } /* }}} */ -/* call request shutdown for all modules */ -static int module_registry_cleanup(zval *zv) /* {{{ */ -{ - zend_module_entry *module = Z_PTR_P(zv); - - if (module->request_shutdown_func) { -#if 0 - zend_printf("%s: Request shutdown\n", module->name); -#endif - module->request_shutdown_func(module->type, module->module_number); - } - return 0; -} -/* }}} */ - ZEND_API void zend_deactivate_modules(void) /* {{{ */ { EG(current_execute_data) = NULL; /* we're no longer executing anything */ zend_try { if (EG(full_tables_cleanup)) { - zend_hash_reverse_apply(&module_registry, module_registry_cleanup); + zend_module_entry *module; + + ZEND_HASH_REVERSE_FOREACH_PTR(&module_registry, module) { + if (module->request_shutdown_func) { +#if 0 + zend_printf("%s: Request shutdown\n", module->name); +#endif + module->request_shutdown_func(module->type, module->module_number); + } + } ZEND_HASH_FOREACH_END(); } else { zend_module_entry **p = module_request_shutdown_handlers; @@ -2664,34 +2594,22 @@ ZEND_API void zend_cleanup_internal_classes(void) /* {{{ */ } /* }}} */ -int module_registry_unload_temp(const zend_module_entry *module) /* {{{ */ -{ - return (module->type == MODULE_TEMPORARY) ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_STOP; -} -/* }}} */ - -static int module_registry_unload_temp_wrapper(zval *el) /* {{{ */ -{ - zend_module_entry *module = (zend_module_entry *)Z_PTR_P(el); - return module_registry_unload_temp((const zend_module_entry *)module); -} -/* }}} */ - -static int exec_done_cb(zval *el) /* {{{ */ -{ - zend_module_entry *module = (zend_module_entry *)Z_PTR_P(el); - if (module->post_deactivate_func) { - module->post_deactivate_func(); - } - return 0; -} -/* }}} */ - ZEND_API void zend_post_deactivate_modules(void) /* {{{ */ { if (EG(full_tables_cleanup)) { - zend_hash_apply(&module_registry, exec_done_cb); - zend_hash_reverse_apply(&module_registry, module_registry_unload_temp_wrapper); + zend_module_entry *module; + + ZEND_HASH_FOREACH_PTR(&module_registry, module) { + if (module->post_deactivate_func) { + module->post_deactivate_func(); + } + } ZEND_HASH_FOREACH_END(); + ZEND_HASH_REVERSE_FOREACH_PTR(&module_registry, module) { + if (module->type != MODULE_TEMPORARY) { + break; + } + module_destructor(module); + } ZEND_HASH_FOREACH_END_DEL(); } else { zend_module_entry **p = module_post_deactivate_handlers; @@ -2720,7 +2638,7 @@ static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class class_entry->type = ZEND_INTERNAL_CLASS; zend_initialize_class_data(class_entry, 0); - class_entry->ce_flags = ce_flags | ZEND_ACC_CONSTANTS_UPDATED; + class_entry->ce_flags = ce_flags | ZEND_ACC_CONSTANTS_UPDATED | ZEND_ACC_LINKED; class_entry->info.internal.module = EG(current_module); if (class_entry->info.internal.builtin_functions) { @@ -2748,6 +2666,7 @@ ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *cla if (parent_ce) { zend_do_inheritance(register_class, parent_ce); + zend_build_properties_info_table(register_class); } return register_class; } @@ -2805,7 +2724,9 @@ ZEND_API int zend_register_class_alias_ex(const char *name, size_t name_len, zen ce = zend_hash_add_ptr(CG(class_table), lcname, ce); zend_string_release_ex(lcname, 0); if (ce) { - ce->refcount++; + if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) { + ce->refcount++; + } return SUCCESS; } return FAILURE; @@ -2836,6 +2757,12 @@ ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_lengt /* Disabled functions support */ +zend_op_array *display_disabled_compile_string(zval *source_string, char *filename) +{ + zend_error(E_WARNING, "eval() has been disabled for security reasons"); + return NULL; +} + /* {{{ proto void display_disabled_function(void) Dummy function which displays an error when a disabled function is called. */ ZEND_API ZEND_FUNCTION(display_disabled_function) @@ -2847,6 +2774,12 @@ ZEND_API ZEND_FUNCTION(display_disabled_function) ZEND_API int zend_disable_function(char *function_name, size_t function_name_length) /* {{{ */ { zend_internal_function *func; + + if (strcmp(function_name, "eval") == 0) { + zend_compile_string = display_disabled_compile_string; + return SUCCESS; + } + if ((func = zend_hash_str_find_ptr(CG(function_table), function_name, function_name_length))) { func->fn_flags &= ~(ZEND_ACC_VARIADIC | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_HAS_RETURN_TYPE); func->num_args = 0; @@ -2959,7 +2892,7 @@ static int zend_is_callable_check_class(zend_string *name, zend_class_entry *sco *strict_class = 1; ret = 1; } - } else if ((ce = zend_lookup_class_ex(name, NULL, 1)) != NULL) { + } else if ((ce = zend_lookup_class(name)) != NULL) { zend_class_entry *scope; zend_execute_data *ex = EG(current_execute_data); @@ -2992,6 +2925,20 @@ static int zend_is_callable_check_class(zend_string *name, zend_class_entry *sco } /* }}} */ +ZEND_API void zend_release_fcall_info_cache(zend_fcall_info_cache *fcc) { + if (fcc->function_handler && + ((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) || + fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY || + fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) { + if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION && + fcc->function_handler->common.function_name) { + zend_string_release_ex(fcc->function_handler->common.function_name, 0); + } + zend_free_trampoline(fcc->function_handler); + } + fcc->function_handler = NULL; +} + static zend_always_inline int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, int strict_class, char **error) /* {{{ */ { zend_class_entry *ce_org = fcc->calling_scope; @@ -3115,24 +3062,17 @@ static zend_always_inline int zend_is_callable_check_func(int check_flags, zval } } } - if ((check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0 && + if (!(fcc->function_handler->common.fn_flags & ZEND_ACC_PUBLIC) && + !(check_flags & IS_CALLABLE_CHECK_NO_ACCESS) && (fcc->calling_scope && ((fcc->object && fcc->calling_scope->__call) || (!fcc->object && fcc->calling_scope->__callstatic)))) { - if (fcc->function_handler->op_array.fn_flags & ZEND_ACC_PRIVATE) { - scope = zend_get_executed_scope(); - if (!zend_check_private(fcc->function_handler, fcc->object ? fcc->object->ce : scope, lmname)) { - retval = 0; - fcc->function_handler = NULL; - goto get_function_via_handler; - } - } else if (fcc->function_handler->common.fn_flags & ZEND_ACC_PROTECTED) { - scope = zend_get_executed_scope(); - if (!zend_check_protected(fcc->function_handler->common.scope, scope)) { - retval = 0; - fcc->function_handler = NULL; - goto get_function_via_handler; - } + scope = zend_get_executed_scope(); + if (fcc->function_handler->common.scope != scope + || !zend_check_protected(zend_get_function_root_class(fcc->function_handler), scope)) { + retval = 0; + fcc->function_handler = NULL; + goto get_function_via_handler; } } } else { @@ -3142,7 +3082,7 @@ get_function_via_handler: fcc->function_handler = zend_get_call_trampoline_func(ce_org, mname, 0); call_via_handler = 1; retval = 1; - } else if (fcc->object->handlers->get_method) { + } else { fcc->function_handler = fcc->object->handlers->get_method(&fcc->object, mname, NULL); if (fcc->function_handler) { if (strict_class && @@ -3218,26 +3158,18 @@ get_function_via_handler: } } } - if (retval && (check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) { - if (fcc->function_handler->op_array.fn_flags & ZEND_ACC_PRIVATE) { - scope = zend_get_executed_scope(); - if (!zend_check_private(fcc->function_handler, fcc->object ? fcc->object->ce : scope, lmname)) { - if (error) { - if (*error) { - efree(*error); - } - zend_spprintf(error, 0, "cannot access private method %s::%s()", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name)); - } - retval = 0; - } - } else if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PROTECTED)) { - scope = zend_get_executed_scope(); - if (!zend_check_protected(fcc->function_handler->common.scope, scope)) { + if (retval + && !(fcc->function_handler->common.fn_flags & ZEND_ACC_PUBLIC) + && !(check_flags & IS_CALLABLE_CHECK_NO_ACCESS)) { + scope = zend_get_executed_scope(); + if (fcc->function_handler->common.scope != scope) { + if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PRIVATE) + || (!zend_check_protected(zend_get_function_root_class(fcc->function_handler), scope))) { if (error) { if (*error) { efree(*error); } - zend_spprintf(error, 0, "cannot access protected method %s::%s()", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name)); + zend_spprintf(error, 0, "cannot access %s method %s::%s()", zend_visibility_string(fcc->function_handler->common.fn_flags), ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name)); } retval = 0; } @@ -3256,6 +3188,10 @@ get_function_via_handler: if (fcc->object) { fcc->called_scope = fcc->object->ce; + if (fcc->function_handler + && fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC) { + fcc->object = NULL; + } } return retval; } @@ -3369,16 +3305,8 @@ again: check_func: ret = zend_is_callable_check_func(check_flags, callable, fcc, strict_class, error); - if (fcc == &fcc_local && - fcc->function_handler && - ((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) || - fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY || - fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) { - if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION && - fcc->function_handler->common.function_name) { - zend_string_release_ex(fcc->function_handler->common.function_name, 0); - } - zend_free_trampoline(fcc->function_handler); + if (fcc == &fcc_local) { + zend_release_fcall_info_cache(fcc); } return ret; @@ -3446,6 +3374,9 @@ check_func: 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 (fcc == &fcc_local) { + zend_release_fcall_info_cache(fcc); + } return 1; } if (error) *error = estrdup("no array or string given"); @@ -3486,15 +3417,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam add_next_index_str(callable, zend_string_copy(fcc.calling_scope->name)); add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name)); } - if (fcc.function_handler && - ((fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) || - fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY || - fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION)) { - if (fcc.function_handler->type != ZEND_OVERLOADED_FUNCTION) { - zend_string_release_ex(fcc.function_handler->common.function_name, 0); - } - zend_free_trampoline(fcc.function_handler); - } + zend_release_fcall_info_cache(&fcc); return 1; } return 0; @@ -3526,7 +3449,7 @@ ZEND_API void zend_fcall_info_args_clear(zend_fcall_info *fci, int free_mem) /* zval *end = p + fci->param_count; while (p != end) { - i_zval_ptr_dtor(p ZEND_FILE_LINE_CC); + i_zval_ptr_dtor(p); p++; } if (free_mem) { @@ -3706,10 +3629,14 @@ static zend_always_inline zend_bool is_persistent_class(zend_class_entry *ce) { && ce->info.internal.module->type == MODULE_PERSISTENT; } -ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment) /* {{{ */ +ZEND_API int zend_declare_typed_property(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, zend_type type) /* {{{ */ { zend_property_info *property_info, *property_info_ptr; + if (ZEND_TYPE_IS_SET(type)) { + ce->ce_flags |= ZEND_ACC_HAS_TYPE_HINTS; + } + if (ce->type == ZEND_INTERNAL_CLASS) { property_info = pemalloc(sizeof(zend_property_info), 1); } else { @@ -3737,8 +3664,14 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS); } ZVAL_COPY_VALUE(&ce->default_static_members_table[property_info->offset], property); - if (ce->type == ZEND_USER_CLASS) { - ce->static_members_table = ce->default_static_members_table; + if (!ZEND_MAP_PTR(ce->static_members_table)) { + ZEND_ASSERT(ce->type == ZEND_INTERNAL_CLASS); + if (!EG(current_execute_data)) { + ZEND_MAP_PTR_NEW(ce->static_members_table); + } else { + /* internal class loaded by dl() */ + ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table); + } } } else { if ((property_info_ptr = zend_hash_find_ptr(&ce->properties_info, name)) != NULL && @@ -3746,10 +3679,20 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z property_info->offset = property_info_ptr->offset; zval_ptr_dtor(&ce->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)]); zend_hash_del(&ce->properties_info, name); + + ZEND_ASSERT(ce->type == ZEND_INTERNAL_CLASS); + ZEND_ASSERT(ce->properties_info_table != NULL); + ce->properties_info_table[OBJ_PROP_TO_NUM(property_info->offset)] = property_info; } else { property_info->offset = OBJ_PROP_TO_OFFSET(ce->default_properties_count); ce->default_properties_count++; ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS); + + /* For user classes this is handled during linking */ + if (ce->type == ZEND_INTERNAL_CLASS) { + ce->properties_info_table = perealloc(ce->properties_info_table, sizeof(zend_property_info *) * ce->default_properties_count, 1); + ce->properties_info_table[ce->default_properties_count - 1] = property_info; + } } ZVAL_COPY_VALUE(&ce->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)], property); } @@ -3781,12 +3724,147 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z property_info->flags = access_type; property_info->doc_comment = doc_comment; property_info->ce = ce; + property_info->type = type; + zend_hash_update_ptr(&ce->properties_info, name, property_info); return SUCCESS; } /* }}} */ +ZEND_API int zend_try_assign_typed_ref_ex(zend_reference *ref, zval *val, zend_bool strict) /* {{{ */ +{ + if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, val, strict))) { + zval_ptr_dtor(val); + return FAILURE; + } else { + zval_ptr_dtor(&ref->val); + ZVAL_COPY_VALUE(&ref->val, val); + return SUCCESS; + } +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref(zend_reference *ref, zval *val) /* {{{ */ +{ + return zend_try_assign_typed_ref_ex(ref, val, ZEND_ARG_USES_STRICT_TYPES()); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_null(zend_reference *ref) /* {{{ */ +{ + zval tmp; + + ZVAL_NULL(&tmp); + return zend_try_assign_typed_ref(ref, &tmp); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_bool(zend_reference *ref, zend_bool val) /* {{{ */ +{ + zval tmp; + + ZVAL_BOOL(&tmp, val); + return zend_try_assign_typed_ref(ref, &tmp); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_long(zend_reference *ref, zend_long lval) /* {{{ */ +{ + zval tmp; + + ZVAL_LONG(&tmp, lval); + return zend_try_assign_typed_ref(ref, &tmp); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_double(zend_reference *ref, double dval) /* {{{ */ +{ + zval tmp; + + ZVAL_DOUBLE(&tmp, dval); + return zend_try_assign_typed_ref(ref, &tmp); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_empty_string(zend_reference *ref) /* {{{ */ +{ + zval tmp; + + ZVAL_EMPTY_STRING(&tmp); + return zend_try_assign_typed_ref(ref, &tmp); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_str(zend_reference *ref, zend_string *str) /* {{{ */ +{ + zval tmp; + + ZVAL_STR(&tmp, str); + return zend_try_assign_typed_ref(ref, &tmp); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_string(zend_reference *ref, const char *string) /* {{{ */ +{ + zval tmp; + + ZVAL_STRING(&tmp, string); + return zend_try_assign_typed_ref(ref, &tmp); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_stringl(zend_reference *ref, const char *string, size_t len) /* {{{ */ +{ + zval tmp; + + ZVAL_STRINGL(&tmp, string, len); + return zend_try_assign_typed_ref(ref, &tmp); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_arr(zend_reference *ref, zend_array *arr) /* {{{ */ +{ + zval tmp; + + ZVAL_ARR(&tmp, arr); + return zend_try_assign_typed_ref(ref, &tmp); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_res(zend_reference *ref, zend_resource *res) /* {{{ */ +{ + zval tmp; + + ZVAL_RES(&tmp, res); + return zend_try_assign_typed_ref(ref, &tmp); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_zval(zend_reference *ref, zval *zv) /* {{{ */ +{ + zval tmp; + + ZVAL_COPY_VALUE(&tmp, zv); + return zend_try_assign_typed_ref(ref, &tmp); +} +/* }}} */ + +ZEND_API int zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval *zv, zend_bool strict) /* {{{ */ +{ + zval tmp; + + ZVAL_COPY_VALUE(&tmp, zv); + return zend_try_assign_typed_ref_ex(ref, &tmp, strict); +} +/* }}} */ + +ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment) /* {{{ */ +{ + return zend_declare_typed_property(ce, name, property, access_type, doc_comment, 0); +} +/* }}} */ + ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, size_t name_length, zval *property, int access_type) /* {{{ */ { zend_string *key = zend_string_init(name, name_length, is_persistent_class(ce)); @@ -3966,9 +4044,6 @@ ZEND_API void zend_update_property_ex(zend_class_entry *scope, zval *object, zen EG(fake_scope) = scope; - if (!Z_OBJ_HT_P(object)->write_property) { - zend_error_noreturn(E_CORE_ERROR, "Property %s of class %s cannot be updated", ZSTR_VAL(name), ZSTR_VAL(Z_OBJCE_P(object)->name)); - } ZVAL_STR(&property, name); Z_OBJ_HT_P(object)->write_property(object, &property, value, NULL); @@ -3983,9 +4058,6 @@ ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const EG(fake_scope) = scope; - if (!Z_OBJ_HT_P(object)->write_property) { - zend_error_noreturn(E_CORE_ERROR, "Property %s of class %s cannot be updated", name, ZSTR_VAL(Z_OBJCE_P(object)->name)); - } ZVAL_STRINGL(&property, name, name_length); Z_OBJ_HT_P(object)->write_property(object, &property, value, NULL); zval_ptr_dtor(&property); @@ -4010,9 +4082,6 @@ ZEND_API void zend_unset_property(zend_class_entry *scope, zval *object, const c EG(fake_scope) = scope; - if (!Z_OBJ_HT_P(object)->unset_property) { - zend_error_noreturn(E_CORE_ERROR, "Property %s of class %s cannot be unset", name, ZSTR_VAL(Z_OBJCE_P(object)->name)); - } ZVAL_STRINGL(&property, name, name_length); Z_OBJ_HT_P(object)->unset_property(object, &property, 0); zval_ptr_dtor(&property); @@ -4079,25 +4148,30 @@ ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object ZEND_API int zend_update_static_property_ex(zend_class_entry *scope, zend_string *name, zval *value) /* {{{ */ { - zval *property; + zval *property, tmp; + zend_property_info *prop_info; zend_class_entry *old_scope = EG(fake_scope); EG(fake_scope) = scope; - property = zend_std_get_static_property(scope, name, 0); + property = zend_std_get_static_property_with_info(scope, name, BP_VAR_W, &prop_info); EG(fake_scope) = old_scope; if (!property) { return FAILURE; } - if (property != value) { - zval garbage; - ZVAL_DEREF(property); - ZVAL_DEREF(value); - ZVAL_COPY_VALUE(&garbage, property); - ZVAL_COPY(property, value); - zval_ptr_dtor(&garbage); + ZEND_ASSERT(!Z_ISREF_P(value)); + Z_TRY_ADDREF_P(value); + if (prop_info->type) { + ZVAL_COPY_VALUE(&tmp, value); + if (!zend_verify_property_type(prop_info, &tmp, /* strict */ 0)) { + Z_TRY_DELREF_P(value); + return FAILURE; + } + value = &tmp; } + + zend_assign_to_variable(property, value, IS_TMP_VAR, /* strict */ 0); return SUCCESS; } /* }}} */ @@ -4174,10 +4248,6 @@ ZEND_API zval *zend_read_property_ex(zend_class_entry *scope, zval *object, zend EG(fake_scope) = scope; - if (!Z_OBJ_HT_P(object)->read_property) { - zend_error_noreturn(E_CORE_ERROR, "Property %s of class %s cannot be read", ZSTR_VAL(name), ZSTR_VAL(Z_OBJCE_P(object)->name)); - } - ZVAL_STR(&property, name); value = Z_OBJ_HT_P(object)->read_property(object, &property, silent?BP_VAR_IS:BP_VAR_R, NULL, rv); @@ -4204,7 +4274,7 @@ ZEND_API zval *zend_read_static_property_ex(zend_class_entry *scope, zend_string zend_class_entry *old_scope = EG(fake_scope); EG(fake_scope) = scope; - property = zend_std_get_static_property(scope, name, silent); + property = zend_std_get_static_property(scope, name, silent ? BP_VAR_IS : BP_VAR_R); EG(fake_scope) = old_scope; return property; @@ -4373,13 +4443,3 @@ ZEND_API zend_bool zend_is_countable(zval *countable) /* {{{ */ } } /* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: t - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ |