From eef1077e4243730014dee30497b9431aead28504 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 6 Feb 2023 15:59:23 +0300 Subject: [PATCH 1/2] Stop copying internal functions into each thread It seems we don't copy internal methods for a long time, so this shouldn't be a problem. We had to copy functions in PHP-5 times, but it seems we just forgot to remove this. It's possible that some third-part extensions (e.g. profilers, tracers, debuggers) modify internal functions. After this change that may cause race conditions in ZTS build (but we already jave the same behavior for internal methods). Observer API should provide necesssary functionality to avoid shared structures modification. --- Zend/zend.c | 18 +++++++++++++++++- Zend/zend_globals.h | 3 +++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Zend/zend.c b/Zend/zend.c index 0eec5f89019d9..b1f6e2efb4ea7 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -756,7 +756,8 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{ compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); zend_hash_init(compiler_globals->function_table, 1024, NULL, ZEND_FUNCTION_DTOR, 1); - zend_hash_copy(compiler_globals->function_table, global_function_table, function_copy_ctor); + zend_hash_copy(compiler_globals->function_table, global_function_table, NULL); + compiler_globals->copied_functions_count = zend_hash_num_elements(compiler_globals->function_table); compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); zend_hash_init(compiler_globals->class_table, 64, NULL, ZEND_CLASS_DTOR, 1); @@ -790,6 +791,21 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{{ */ { if (compiler_globals->function_table != GLOBAL_FUNCTION_TABLE) { + uint32_t n = compiler_globals->copied_functions_count; + + /* Prevent destruction of functions copied from the main process context */ + if (zend_hash_num_elements(compiler_globals->function_table) <= n) { + compiler_globals->function_table->nNumUsed = 0; + } else { + Bucket *p = compiler_globals->function_table->arData; + + compiler_globals->function_table->nNumOfElements -= n; + while (n != 0) { + ZVAL_UNDEF(&p->val); + p++; + n--; + } + } zend_hash_destroy(compiler_globals->function_table); free(compiler_globals->function_table); } diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 6fca08e82d3ca..9c109e967cd50 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -144,6 +144,9 @@ struct _zend_compiler_globals { uint32_t rtd_key_counter; zend_stack short_circuiting_opnums; +#ifdef ZTS + uint32_t copied_functions_count; +#endif }; From a736b5651a19f9aedc41137946015bc5c54b559d Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 6 Feb 2023 16:16:36 +0300 Subject: [PATCH 2/2] Remove unused function --- Zend/zend.c | 63 ----------------------------------------------------- 1 file changed, 63 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index b1f6e2efb4ea7..4f40ebc4f95a0 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -674,69 +674,6 @@ static void auto_global_dtor(zval *zv) /* {{{ */ /* }}} */ #ifdef ZTS -static void function_copy_ctor(zval *zv) /* {{{ */ -{ - zend_function *old_func = Z_FUNC_P(zv); - zend_function *func; - - if (old_func->type == ZEND_USER_FUNCTION) { - ZEND_ASSERT(old_func->op_array.fn_flags & ZEND_ACC_IMMUTABLE); - return; - } - func = pemalloc(sizeof(zend_internal_function), 1); - Z_FUNC_P(zv) = func; - memcpy(func, old_func, sizeof(zend_internal_function)); - function_add_ref(func); - if ((old_func->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) - && old_func->common.arg_info) { - uint32_t i; - uint32_t num_args = old_func->common.num_args + 1; - zend_arg_info *arg_info = old_func->common.arg_info - 1; - zend_arg_info *new_arg_info; - - if (old_func->common.fn_flags & ZEND_ACC_VARIADIC) { - num_args++; - } - new_arg_info = pemalloc(sizeof(zend_arg_info) * num_args, 1); - memcpy(new_arg_info, arg_info, sizeof(zend_arg_info) * num_args); - for (i = 0 ; i < num_args; i++) { - if (ZEND_TYPE_HAS_LIST(arg_info[i].type)) { - zend_type_list *old_list = ZEND_TYPE_LIST(arg_info[i].type); - zend_type_list *new_list = pemalloc(ZEND_TYPE_LIST_SIZE(old_list->num_types), 1); - memcpy(new_list, old_list, ZEND_TYPE_LIST_SIZE(old_list->num_types)); - ZEND_TYPE_SET_PTR(new_arg_info[i].type, new_list); - - zend_type *list_type; - ZEND_TYPE_LIST_FOREACH(new_list, list_type) { - zend_string *name = zend_string_dup(ZEND_TYPE_NAME(*list_type), 1); - ZEND_TYPE_SET_PTR(*list_type, name); - } ZEND_TYPE_LIST_FOREACH_END(); - } else if (ZEND_TYPE_HAS_NAME(arg_info[i].type)) { - zend_string *name = zend_string_dup(ZEND_TYPE_NAME(arg_info[i].type), 1); - ZEND_TYPE_SET_PTR(new_arg_info[i].type, name); - } - } - func->common.arg_info = new_arg_info + 1; - } - if (old_func->common.attributes) { - zend_attribute *old_attr; - - func->common.attributes = NULL; - - ZEND_HASH_PACKED_FOREACH_PTR(old_func->common.attributes, old_attr) { - uint32_t i; - zend_attribute *attr; - - attr = zend_add_attribute(&func->common.attributes, old_attr->name, old_attr->argc, old_attr->flags, old_attr->offset, old_attr->lineno); - - for (i = 0 ; i < old_attr->argc; i++) { - ZVAL_DUP(&attr->args[i].value, &old_attr->args[i].value); - } - } ZEND_HASH_FOREACH_END(); - } -} -/* }}} */ - static void auto_global_copy_ctor(zval *zv) /* {{{ */ { zend_auto_global *old_ag = (zend_auto_global *) Z_PTR_P(zv);