summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-08-28 12:32:22 +0200
committerNikita Popov <nikita.ppv@gmail.com>2019-08-28 12:32:22 +0200
commit3f339ec15f5ea52c4bad62c209aff86c5de83b7e (patch)
treec045cff5dd99af882a3f5b6098dd61c0861a7851
parent937d5f6598036d48713e28bf68df52cd56e1c974 (diff)
parentec9a96dc60c3fd2cccf5b21033a0e87807366bdb (diff)
downloadphp-git-3f339ec15f5ea52c4bad62c209aff86c5de83b7e.tar.gz
Merge branch 'PHP-7.4'
-rw-r--r--Zend/tests/bug78335.phpt28
-rw-r--r--Zend/zend_execute_API.c93
2 files changed, 73 insertions, 48 deletions
diff --git a/Zend/tests/bug78335.phpt b/Zend/tests/bug78335.phpt
new file mode 100644
index 0000000000..68e885885e
--- /dev/null
+++ b/Zend/tests/bug78335.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Bug #78335: Static properties/variables containing cycles report as leak
+--FILE--
+<?php
+
+class Test {
+ public static $test;
+
+ public static function method() {
+ static $foo;
+ $foo = [&$foo];
+ }
+}
+
+function test() {
+ static $foo;
+ $foo = [&$foo];
+}
+
+$foo = [&$foo];
+Test::$test = $foo;
+test();
+Test::method();
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index f960d856b0..1465e9afd3 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -268,9 +268,54 @@ void shutdown_executor(void) /* {{{ */
zend_close_rsrc_list(&EG(regular_list));
} zend_end_try();
+ /* No PHP callback functions should be called after this point. */
+ EG(active) = 0;
+
if (!fast_shutdown) {
zend_hash_graceful_reverse_destroy(&EG(symbol_table));
+ /* Release static properties and static variables prior to the final GC run,
+ * as they may hold GC roots. */
+ ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) {
+ zend_op_array *op_array = Z_PTR_P(zv);
+ if (op_array->type == ZEND_INTERNAL_FUNCTION) {
+ break;
+ }
+ if (op_array->static_variables) {
+ HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
+ if (ht) {
+ ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
+ zend_array_destroy(ht);
+ ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
+ ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
+ zend_class_entry *ce = Z_PTR_P(zv);
+ if (ce->type == ZEND_INTERNAL_CLASS) {
+ break;
+ }
+ if (ce->default_static_members_count) {
+ zend_cleanup_internal_class_data(ce);
+ }
+ if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
+ zend_op_array *op_array;
+ ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
+ if (op_array->type == ZEND_USER_FUNCTION) {
+ if (op_array->static_variables) {
+ HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
+ if (ht) {
+ if (GC_DELREF(ht) == 0) {
+ zend_array_destroy(ht);
+ }
+ ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
+ }
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+ } ZEND_HASH_FOREACH_END();
+
#if ZEND_DEBUG
if (gc_enabled() && !CG(unclean_shutdown)) {
gc_collect_cycles();
@@ -282,10 +327,6 @@ void shutdown_executor(void) /* {{{ */
zend_weakrefs_shutdown();
- /* All resources and objects are destroyed. */
- /* No PHP callback functions may be called after this point. */
- EG(active) = 0;
-
zend_try {
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
} zend_end_try();
@@ -346,23 +387,6 @@ void shutdown_executor(void) /* {{{ */
zend_string_release_ex(key, 0);
} ZEND_HASH_FOREACH_END_DEL();
- /* Cleanup preloaded immutable functions */
- ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) {
- zend_op_array *op_array = Z_PTR_P(zv);
- if (op_array->type == ZEND_INTERNAL_FUNCTION) {
- break;
- }
- ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_IMMUTABLE);
- if (op_array->static_variables) {
- HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
- if (ht) {
- ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
- zend_array_destroy(ht);
- ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
- }
- }
- } ZEND_HASH_FOREACH_END();
-
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
if (_idx == EG(persistent_classes_count)) {
break;
@@ -370,33 +394,6 @@ void shutdown_executor(void) /* {{{ */
destroy_zend_class(zv);
zend_string_release_ex(key, 0);
} ZEND_HASH_FOREACH_END_DEL();
-
- /* Cleanup preloaded immutable classes */
- ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
- zend_class_entry *ce = Z_PTR_P(zv);
- if (ce->type == ZEND_INTERNAL_CLASS) {
- break;
- }
- ZEND_ASSERT(ce->ce_flags & ZEND_ACC_IMMUTABLE);
- if (ce->default_static_members_count) {
- zend_cleanup_internal_class_data(ce);
- }
- if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
- zend_op_array *op_array;
- ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
- if (op_array->type == ZEND_USER_FUNCTION) {
- if (op_array->static_variables) {
- HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
- if (ht) {
- ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
- zend_array_destroy(ht);
- ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
- }
- }
- }
- } ZEND_HASH_FOREACH_END();
- }
- } ZEND_HASH_FOREACH_END();
}
zend_cleanup_internal_classes();