mirror of
https://github.com/php/php-src.git
synced 2025-08-16 14:08:47 +02:00
Fixed bug #78335
Destroy static properties and variables prior to the final GC run, as they may hold GC roots.
This commit is contained in:
parent
8dfd3af169
commit
ec9a96dc60
3 changed files with 75 additions and 48 deletions
2
NEWS
2
NEWS
|
@ -11,6 +11,8 @@ PHP NEWS
|
||||||
(cmb)
|
(cmb)
|
||||||
. Fixed bug #78454 (Consecutive numeric separators cause OOM error).
|
. Fixed bug #78454 (Consecutive numeric separators cause OOM error).
|
||||||
(Theodore Brown)
|
(Theodore Brown)
|
||||||
|
. Fixed bug #78335 (Static properties/variables containing cycles report as
|
||||||
|
leak). (Nikita)
|
||||||
|
|
||||||
- FPM:
|
- FPM:
|
||||||
. Fixed bug #78334 (fpm log prefix message includes wrong stdout/stderr
|
. Fixed bug #78334 (fpm log prefix message includes wrong stdout/stderr
|
||||||
|
|
28
Zend/tests/bug78335.phpt
Normal file
28
Zend/tests/bug78335.phpt
Normal file
|
@ -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===
|
|
@ -270,9 +270,54 @@ void shutdown_executor(void) /* {{{ */
|
||||||
zend_close_rsrc_list(&EG(regular_list));
|
zend_close_rsrc_list(&EG(regular_list));
|
||||||
} zend_end_try();
|
} zend_end_try();
|
||||||
|
|
||||||
|
/* No PHP callback functions should be called after this point. */
|
||||||
|
EG(active) = 0;
|
||||||
|
|
||||||
if (!fast_shutdown) {
|
if (!fast_shutdown) {
|
||||||
zend_hash_graceful_reverse_destroy(&EG(symbol_table));
|
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 ZEND_DEBUG
|
||||||
if (gc_enabled() && !CG(unclean_shutdown)) {
|
if (gc_enabled() && !CG(unclean_shutdown)) {
|
||||||
gc_collect_cycles();
|
gc_collect_cycles();
|
||||||
|
@ -284,10 +329,6 @@ void shutdown_executor(void) /* {{{ */
|
||||||
|
|
||||||
zend_weakrefs_shutdown();
|
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_try {
|
||||||
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
|
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
|
||||||
} zend_end_try();
|
} zend_end_try();
|
||||||
|
@ -348,23 +389,6 @@ void shutdown_executor(void) /* {{{ */
|
||||||
zend_string_release_ex(key, 0);
|
zend_string_release_ex(key, 0);
|
||||||
} ZEND_HASH_FOREACH_END_DEL();
|
} 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) {
|
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
|
||||||
if (_idx == EG(persistent_classes_count)) {
|
if (_idx == EG(persistent_classes_count)) {
|
||||||
break;
|
break;
|
||||||
|
@ -372,33 +396,6 @@ void shutdown_executor(void) /* {{{ */
|
||||||
destroy_zend_class(zv);
|
destroy_zend_class(zv);
|
||||||
zend_string_release_ex(key, 0);
|
zend_string_release_ex(key, 0);
|
||||||
} ZEND_HASH_FOREACH_END_DEL();
|
} 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();
|
zend_cleanup_internal_classes();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue