]> granicus.if.org Git - php/commitdiff
Memory leak fix, for arg_info of internal functions with type hints (ZTS build only).
authorDmitry Stogov <dmitry@zend.com>
Tue, 6 Mar 2018 11:59:30 +0000 (14:59 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 6 Mar 2018 11:59:30 +0000 (14:59 +0300)
Zend/zend.c
Zend/zend_opcode.c

index 09b7454468d91f5a9b2ed7c642745eb38755dd8c..98d8a803dbede471eb08bbf7fc7f67bf1db713f1 100644 (file)
@@ -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;
+       }
 }
 /* }}} */
 
index 11194bc51c10a71c8b98a29ff6370eaa4a198ab1..5e7164c3245aebadff25848c67dcfa5398776a19 100644 (file)
@@ -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;