From a7f83f474cb9fcec5db08a25da58a63d03a5b5dc Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 6 Mar 2018 14:59:30 +0300 Subject: [PATCH] Memory leak fix, for arg_info of internal functions with type hints (ZTS build only). --- Zend/zend.c | 31 ++++++++++++++++++++++++++++--- Zend/zend_opcode.c | 11 +++++------ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index 09b7454468..98d8a803db 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -570,9 +570,34 @@ static void auto_global_dtor(zval *zv) /* {{{ */ static void function_copy_ctor(zval *zv) /* {{{ */ { zend_function *old_func = Z_FUNC_P(zv); - Z_FUNC_P(zv) = pemalloc(sizeof(zend_internal_function), 1); - memcpy(Z_FUNC_P(zv), old_func, sizeof(zend_internal_function)); - function_add_ref(Z_FUNC_P(zv)); + zend_function *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_IS_CLASS(arg_info[i].type)) { + zend_string *name = zend_string_dup(ZEND_TYPE_NAME(arg_info[i].type), 1); + + new_arg_info[i].type = + ZEND_TYPE_ENCODE_CLASS( + name, ZEND_TYPE_ALLOW_NULL(arg_info[i].type)); + } + } + func->common.arg_info = new_arg_info + 1; + } } /* }}} */ diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 11194bc51c..5e7164c324 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -141,7 +141,7 @@ ZEND_API void zend_function_dtor(zval *zv) ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(function->common.function_name); zend_string_release(function->common.function_name); -#ifndef ZTS + if ((function->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) && !function->common.scope && function->common.arg_info) { @@ -159,7 +159,7 @@ ZEND_API void zend_function_dtor(zval *zv) } free(arg_info); } -#endif + if (!(function->common.fn_flags & ZEND_ACC_ARENA_ALLOCATED)) { pefree(function, 1); } @@ -245,9 +245,7 @@ ZEND_API void destroy_zend_class(zval *zv) { zend_property_info *prop_info; zend_class_entry *ce = Z_PTR_P(zv); -#ifndef ZTS zend_function *fn; -#endif if (--ce->refcount > 0) { return; @@ -331,7 +329,8 @@ ZEND_API void destroy_zend_class(zval *zv) } zend_hash_destroy(&ce->properties_info); zend_string_release(ce->name); -#ifndef ZTS + + /* TODO: eliminate this loop for classes without functions with arg_info */ ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) { if ((fn->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) && fn->common.scope == ce) { @@ -339,7 +338,7 @@ ZEND_API void destroy_zend_class(zval *zv) fn->common.scope = NULL; } } ZEND_HASH_FOREACH_END(); -#endif + zend_hash_destroy(&ce->function_table); if (zend_hash_num_elements(&ce->constants_table)) { zend_class_constant *c; -- 2.50.1