summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2021-03-18 10:14:32 +0100
committerNikita Popov <nikita.ppv@gmail.com>2021-03-18 10:31:28 +0100
commit234af00bcb93e0be1d9b17ab3f2d366b09a99611 (patch)
tree49fc5fe3a23f38bae2104936d480a46c8618a1ba /Zend
parent7e9f6d2a48f8ff6ae458252d395eec1b1d9e6f14 (diff)
downloadphp-git-234af00bcb93e0be1d9b17ab3f2d366b09a99611.tar.gz
Destroy constant values before object store
Now that constants can contain objects (currently only enums), we should destroy them before we free the object store, otherwise there will be false positive leak reports. This doesn't affect the fast_shutdown sequence.
Diffstat (limited to 'Zend')
-rw-r--r--Zend/zend_execute_API.c44
-rw-r--r--Zend/zend_objects_API.c5
2 files changed, 30 insertions, 19 deletions
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index f61a865ddc..ce51ef7960 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -278,6 +278,24 @@ void shutdown_executor(void) /* {{{ */
if (!fast_shutdown) {
zend_hash_graceful_reverse_destroy(&EG(symbol_table));
+ /* Constants may contain objects, destroy them before the object store. */
+ if (EG(full_tables_cleanup)) {
+ zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant_full);
+ } else {
+ ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(zend_constants), key, zv) {
+ zend_constant *c = Z_PTR_P(zv);
+ if (_idx == EG(persistent_constants_count)) {
+ break;
+ }
+ zval_ptr_dtor_nogc(&c->value);
+ if (c->name) {
+ zend_string_release_ex(c->name, 0);
+ }
+ efree(c);
+ zend_string_release_ex(key, 0);
+ } ZEND_HASH_FOREACH_END_DEL();
+ }
+
/* 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) {
@@ -302,6 +320,15 @@ void shutdown_executor(void) /* {{{ */
if (ZEND_MAP_PTR(ce->mutable_data) && ZEND_MAP_PTR_GET_IMM(ce->mutable_data)) {
zend_cleanup_mutable_class_data(ce);
+ } else if (ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
+ /* Constants may contain objects, destroy the values before the object store. */
+ zend_class_constant *c;
+ ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
+ if (c->ce == ce) {
+ zval_ptr_dtor_nogc(&c->value);
+ ZVAL_UNDEF(&c->value);
+ }
+ } ZEND_HASH_FOREACH_END();
}
if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
@@ -340,6 +367,8 @@ void shutdown_executor(void) /* {{{ */
gc_collect_cycles();
}
#endif
+ } else {
+ zend_hash_discard(EG(zend_constants), EG(persistent_constants_count));
}
zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown);
@@ -356,7 +385,6 @@ void shutdown_executor(void) /* {{{ */
* Zend Memory Manager frees memory by its own. We don't have to free
* each allocated block separately.
*/
- zend_hash_discard(EG(zend_constants), EG(persistent_constants_count));
zend_hash_discard(EG(function_table), EG(persistent_functions_count));
zend_hash_discard(EG(class_table), EG(persistent_classes_count));
zend_cleanup_internal_classes();
@@ -364,23 +392,9 @@ void shutdown_executor(void) /* {{{ */
zend_vm_stack_destroy();
if (EG(full_tables_cleanup)) {
- zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant_full);
zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full);
} else {
- ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(zend_constants), key, zv) {
- zend_constant *c = Z_PTR_P(zv);
- if (_idx == EG(persistent_constants_count)) {
- break;
- }
- zval_ptr_dtor_nogc(&c->value);
- if (c->name) {
- zend_string_release_ex(c->name, 0);
- }
- efree(c);
- zend_string_release_ex(key, 0);
- } ZEND_HASH_FOREACH_END_DEL();
-
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(function_table), key, zv) {
zend_function *func = Z_PTR_P(zv);
if (_idx == EG(persistent_functions_count)) {
diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c
index b0e9d2f8a8..104cda6141 100644
--- a/Zend/zend_objects_API.c
+++ b/Zend/zend_objects_API.c
@@ -113,10 +113,7 @@ ZEND_API void ZEND_FASTCALL zend_objects_store_free_object_storage(zend_objects_
if (IS_OBJ_VALID(obj)) {
if (!(OBJ_FLAGS(obj) & IS_OBJ_FREE_CALLED)) {
GC_ADD_FLAGS(obj, IS_OBJ_FREE_CALLED);
- // FIXME: This causes constant objects to leak
- if (!(obj->ce->ce_flags & ZEND_ACC_ENUM)) {
- GC_ADDREF(obj);
- }
+ GC_ADDREF(obj);
obj->handlers->free_obj(obj);
}
}