From 1314ccbf8c3731f000e2c32f34dad21b053333f3 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 26 Jun 2020 10:54:40 +0200 Subject: [PATCH] Cache __unserialize() instead of unserialize() We should use these cache slots for the new object serialization mechanism rather than the old one. --- Zend/zend.h | 4 ++-- Zend/zend_API.c | 16 ++++++++-------- Zend/zend_API.h | 4 ++-- Zend/zend_compile.c | 14 ++++++-------- Zend/zend_inheritance.c | 20 ++++++++++---------- Zend/zend_interfaces.c | 7 ++++--- ext/opcache/zend_accelerator_util_funcs.c | 8 ++------ ext/opcache/zend_file_cache.c | 8 ++++---- ext/opcache/zend_persist.c | 12 ++++++------ ext/standard/var.c | 12 ++++-------- ext/standard/var_unserializer.re | 19 ++++++------------- 11 files changed, 54 insertions(+), 70 deletions(-) diff --git a/Zend/zend.h b/Zend/zend.h index 997f2e7053..4fe89fcacc 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -140,8 +140,8 @@ struct _zend_class_entry { zend_function *__callstatic; zend_function *__tostring; zend_function *__debugInfo; - zend_function *serialize_func; - zend_function *unserialize_func; + zend_function *__serialize; + zend_function *__unserialize; /* allocated only if class implements Iterator or IteratorAggregate interface */ zend_class_iterator_funcs *iterator_funcs_ptr; diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 1d18b047d3..14075847ad 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2056,7 +2056,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, *serialize_func = NULL, *unserialize_func = 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 = NULL, *__unserialize = NULL; zend_string *lowercase_name; size_t fname_len; const char *lc_class_name = NULL; @@ -2222,11 +2222,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio if (scope) { /* Look for ctor, dtor, clone */ - 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] != '_') { + 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)) { ctor = reg_function; @@ -2257,6 +2253,10 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio scope->ce_flags |= ZEND_ACC_USE_GUARDS; } else if (zend_string_equals_literal(lowercase_name, ZEND_DEBUGINFO_FUNC_NAME)) { __debugInfo = reg_function; + } else if (zend_string_equals_literal(lowercase_name, "__serialize")) { + __serialize = reg_function; + } else if (zend_string_equals_literal(lowercase_name, "__unserialize")) { + __unserialize = reg_function; } else { reg_function = NULL; } @@ -2298,8 +2298,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; + scope->__serialize = __serialize; + scope->__unserialize = __unserialize; if (ctor) { ctor->common.fn_flags |= ZEND_ACC_CTOR; if (ctor->common.fn_flags & ZEND_ACC_STATIC) { diff --git a/Zend/zend_API.h b/Zend/zend_API.h index bdcdfaea31..9744612ac7 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -250,8 +250,8 @@ typedef struct _zend_fcall_info_cache { class_container.__unset = NULL; \ class_container.__isset = NULL; \ class_container.__debugInfo = NULL; \ - class_container.serialize_func = NULL; \ - class_container.unserialize_func = NULL; \ + class_container.__serialize = NULL; \ + class_container.__unserialize = NULL; \ class_container.parent = NULL; \ class_container.num_interfaces = 0; \ class_container.trait_names = NULL; \ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f65e4a94ec..de5b8581e8 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1835,6 +1835,9 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify ce->__call = NULL; ce->__callstatic = NULL; ce->__tostring = NULL; + ce->__serialize = NULL; + ce->__unserialize = NULL; + ce->__debugInfo = NULL; ce->create_object = NULL; ce->get_iterator = NULL; ce->iterator_funcs_ptr = NULL; @@ -1849,9 +1852,6 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify ce->trait_precedences = NULL; ce->serialize = NULL; ce->unserialize = NULL; - ce->serialize_func = NULL; - ce->unserialize_func = NULL; - ce->__debugInfo = NULL; if (ce->type == ZEND_INTERNAL_CLASS) { ce->info.internal.module = NULL; ce->info.internal.builtin_functions = NULL; @@ -6256,11 +6256,7 @@ zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name, ZSTR_VAL(ce->name), ZSTR_VAL(name)); } - if (zend_string_equals_literal(lcname, "serialize")) { - ce->serialize_func = (zend_function *) op_array; - } else if (zend_string_equals_literal(lcname, "unserialize")) { - ce->unserialize_func = (zend_function *) op_array; - } else if (ZSTR_VAL(lcname)[0] != '_' || ZSTR_VAL(lcname)[1] != '_') { + if (ZSTR_VAL(lcname)[0] != '_' || ZSTR_VAL(lcname)[1] != '_') { /* pass */ } else if (zend_string_equals_literal(lcname, ZEND_CONSTRUCTOR_FUNC_NAME)) { ce->constructor = (zend_function *) op_array; @@ -6301,8 +6297,10 @@ zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name, ce->__debugInfo = (zend_function *) op_array; } else if (zend_string_equals_literal(lcname, "__serialize")) { zend_check_magic_method_attr(fn_flags, ce, "__serialize", 0); + ce->__serialize = (zend_function *) op_array; } else if (zend_string_equals_literal(lcname, "__unserialize")) { zend_check_magic_method_attr(fn_flags, ce, "__unserialize", 0); + ce->__unserialize = (zend_function *) op_array; } else if (zend_string_equals_literal(lcname, "__set_state")) { zend_check_magic_method_attr(fn_flags, ce, "__set_state", 1); } diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 7cee42085b..8a3c9ba1aa 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -167,15 +167,15 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */ if (EXPECTED(!ce->clone)) { ce->clone = parent->clone; } - if (EXPECTED(!ce->serialize_func)) { - ce->serialize_func = parent->serialize_func; + if (EXPECTED(!ce->__serialize)) { + ce->__serialize = parent->__serialize; + } + if (EXPECTED(!ce->__unserialize)) { + ce->__unserialize = parent->__unserialize; } if (EXPECTED(!ce->serialize)) { ce->serialize = parent->serialize; } - if (EXPECTED(!ce->unserialize_func)) { - ce->unserialize_func = parent->unserialize_func; - } if (EXPECTED(!ce->unserialize)) { ce->unserialize = parent->unserialize; } @@ -1557,11 +1557,7 @@ static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zend_function* fe) /* {{{ */ { - if (zend_string_equals_literal(mname, "serialize")) { - ce->serialize_func = fe; - } else if (zend_string_equals_literal(mname, "unserialize")) { - ce->unserialize_func = fe; - } else if (ZSTR_VAL(mname)[0] != '_' || ZSTR_VAL(mname)[1] != '_') { + if (ZSTR_VAL(mname)[0] != '_' || ZSTR_VAL(mname)[1] != '_') { /* pass */ } else if (zend_string_equals_literal(mname, ZEND_CLONE_FUNC_NAME)) { ce->clone = fe; @@ -1589,6 +1585,10 @@ static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zen ce->__tostring = fe; } else if (zend_string_equals_literal(mname, ZEND_DEBUGINFO_FUNC_NAME)) { ce->__debugInfo = fe; + } else if (zend_string_equals_literal(mname, "__serialize")) { + ce->__serialize = fe; + } else if (zend_string_equals_literal(mname, "__unserialize")) { + ce->__unserialize = fe; } } /* }}} */ diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index 3009af2b3f..a100176c36 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -357,7 +357,8 @@ ZEND_API int zend_user_serialize(zval *object, unsigned char **buffer, size_t *b zval retval; int result; - zend_call_known_instance_method_with_0_params(ce->serialize_func, Z_OBJ_P(object), &retval); + zend_call_method_with_0_params( + Z_OBJ_P(object), Z_OBJCE_P(object), NULL, "serialize", &retval); if (Z_TYPE(retval) == IS_UNDEF || EG(exception)) { result = FAILURE; @@ -396,8 +397,8 @@ ZEND_API int zend_user_unserialize(zval *object, zend_class_entry *ce, const uns } ZVAL_STRINGL(&zdata, (char*)buf, buf_len); - zend_call_known_instance_method_with_1_params( - ce->unserialize_func, Z_OBJ_P(object), NULL, &zdata); + zend_call_method_with_1_params( + Z_OBJ_P(object), Z_OBJCE_P(object), NULL, "unserialize", NULL, &zdata); zval_ptr_dtor(&zdata); if (EG(exception)) { diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index db2ee8c434..cfd70eec12 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -369,17 +369,13 @@ static void zend_class_copy_ctor(zend_class_entry **pce) zend_update_inherited_handler(__get); zend_update_inherited_handler(__set); zend_update_inherited_handler(__call); -/* 5.1 stuff */ - zend_update_inherited_handler(serialize_func); - zend_update_inherited_handler(unserialize_func); zend_update_inherited_handler(__isset); zend_update_inherited_handler(__unset); -/* 5.2 stuff */ zend_update_inherited_handler(__tostring); - -/* 5.3 stuff */ zend_update_inherited_handler(__callstatic); zend_update_inherited_handler(__debugInfo); + zend_update_inherited_handler(__serialize); + zend_update_inherited_handler(__unserialize); /* 5.4 traits */ if (ce->num_traits) { diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 7bf36b7931..15ade4ce3c 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -827,8 +827,8 @@ static void zend_file_cache_serialize_class(zval *zv, SERIALIZE_PTR(ce->__get); SERIALIZE_PTR(ce->__set); SERIALIZE_PTR(ce->__call); - SERIALIZE_PTR(ce->serialize_func); - SERIALIZE_PTR(ce->unserialize_func); + SERIALIZE_PTR(ce->__serialize); + SERIALIZE_PTR(ce->__unserialize); SERIALIZE_PTR(ce->__isset); SERIALIZE_PTR(ce->__unset); SERIALIZE_PTR(ce->__tostring); @@ -1564,8 +1564,8 @@ static void zend_file_cache_unserialize_class(zval *zv, UNSERIALIZE_PTR(ce->__get); UNSERIALIZE_PTR(ce->__set); UNSERIALIZE_PTR(ce->__call); - UNSERIALIZE_PTR(ce->serialize_func); - UNSERIALIZE_PTR(ce->unserialize_func); + UNSERIALIZE_PTR(ce->__serialize); + UNSERIALIZE_PTR(ce->__unserialize); UNSERIALIZE_PTR(ce->__isset); UNSERIALIZE_PTR(ce->__unset); UNSERIALIZE_PTR(ce->__tostring); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 1ad195c689..ae997b9a60 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -1090,16 +1090,16 @@ static void zend_update_parent_ce(zend_class_entry *ce) ce->__call = tmp; } } - if (ce->serialize_func) { - zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->serialize_func); + if (ce->__serialize) { + zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__serialize); if (tmp != NULL) { - ce->serialize_func = tmp; + ce->__serialize = tmp; } } - if (ce->unserialize_func) { - zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->unserialize_func); + if (ce->__unserialize) { + zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__unserialize); if (tmp != NULL) { - ce->unserialize_func = tmp; + ce->__unserialize = tmp; } } if (ce->__isset) { diff --git a/ext/standard/var.c b/ext/standard/var.c index 4d47e67e2c..d96f373543 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -743,16 +743,12 @@ static int php_var_serialize_call_sleep(zval *retval, zval *struc) /* {{{ */ static int php_var_serialize_call_magic_serialize(zval *retval, zval *obj) /* {{{ */ { - zval fname; - int res; - - ZVAL_STRINGL(&fname, "__serialize", sizeof("__serialize") - 1); BG(serialize_lock)++; - res = call_user_function(CG(function_table), obj, &fname, retval, 0, 0); + zend_call_known_instance_method_with_0_params( + Z_OBJCE_P(obj)->__serialize, Z_OBJ_P(obj), retval); BG(serialize_lock)--; - zval_ptr_dtor_str(&fname); - if (res == FAILURE || Z_ISUNDEF_P(retval)) { + if (EG(exception)) { zval_ptr_dtor(retval); return FAILURE; } @@ -995,7 +991,7 @@ again: zend_bool incomplete_class; uint32_t count; - if (zend_hash_str_exists(&ce->function_table, "__serialize", sizeof("__serialize")-1)) { + if (ce->__serialize) { zval retval, obj; zend_string *key; zval *data; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 8766b3f2f1..9aadaf5843 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -218,9 +218,8 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) var_entries *var_hash = (*var_hashx)->entries.next; var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor; zend_bool delayed_call_failed = 0; - zval wakeup_name, unserialize_name; + zval wakeup_name; ZVAL_UNDEF(&wakeup_name); - ZVAL_UNDEF(&unserialize_name); #if VAR_ENTRIES_DBG fprintf(stderr, "var_destroy( " ZEND_LONG_FMT ")\n", var_hash?var_hash->used_slots:-1L); @@ -261,22 +260,18 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) } else if (Z_EXTRA_P(zv) == VAR_UNSERIALIZE_FLAG) { /* Perform delayed __unserialize calls */ if (!delayed_call_failed) { - zval retval, param; + zval param; ZVAL_COPY(¶m, &var_dtor_hash->data[i + 1]); - if (Z_ISUNDEF(unserialize_name)) { - ZVAL_STRINGL(&unserialize_name, "__unserialize", sizeof("__unserialize") - 1); - } - BG(serialize_lock)++; - if (call_user_function(CG(function_table), zv, &unserialize_name, &retval, 1, ¶m) == FAILURE || Z_ISUNDEF(retval)) { + zend_call_known_instance_method_with_1_params( + Z_OBJCE_P(zv)->__unserialize, Z_OBJ_P(zv), NULL, ¶m); + if (EG(exception)) { delayed_call_failed = 1; GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED); } BG(serialize_lock)--; - zval_ptr_dtor(¶m); - zval_ptr_dtor(&retval); } else { GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED); } @@ -290,7 +285,6 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) } zval_ptr_dtor_nogc(&wakeup_name); - zval_ptr_dtor_nogc(&unserialize_name); if ((*var_hashx)->ref_props) { zend_hash_destroy((*var_hashx)->ref_props); @@ -1169,8 +1163,7 @@ object ":" uiv ":" ["] { *p += 2; - has_unserialize = !incomplete_class - && zend_hash_str_exists(&ce->function_table, "__unserialize", sizeof("__unserialize")-1); + has_unserialize = !incomplete_class && ce->__unserialize; /* If this class implements Serializable, it should not land here but in object_custom(). * The passed string obviously doesn't descend from the regular serializer. However, if -- 2.40.0