From 2709d6a2508abfdda1b84f0426ae644c703180ed Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 28 Aug 2019 15:33:51 +0200 Subject: [PATCH 1/2] Destroy error handlers before final GC run --- Zend/zend_execute_API.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index ac2ee8ed7f6..210817fef19 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -318,6 +318,21 @@ void shutdown_executor(void) /* {{{ */ } } ZEND_HASH_FOREACH_END(); + /* Also release error and exception handlers, which may hold objects. */ + if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { + zval_ptr_dtor(&EG(user_error_handler)); + ZVAL_UNDEF(&EG(user_error_handler)); + } + + if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { + zval_ptr_dtor(&EG(user_exception_handler)); + ZVAL_UNDEF(&EG(user_exception_handler)); + } + + zend_stack_clean(&EG(user_error_handlers_error_reporting), NULL, 1); + zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1); + zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1); + #if ZEND_DEBUG if (gc_enabled() && !CG(unclean_shutdown)) { gc_collect_cycles(); @@ -344,22 +359,6 @@ void shutdown_executor(void) /* {{{ */ zend_hash_discard(EG(class_table), EG(persistent_classes_count)); zend_cleanup_internal_classes(); } else { - /* remove error handlers before destroying classes and functions, - * so that if handler used some class, crash would not happen */ - if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { - zval_ptr_dtor(&EG(user_error_handler)); - ZVAL_UNDEF(&EG(user_error_handler)); - } - - if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { - zval_ptr_dtor(&EG(user_exception_handler)); - ZVAL_UNDEF(&EG(user_exception_handler)); - } - - zend_stack_clean(&EG(user_error_handlers_error_reporting), NULL, 1); - zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1); - zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1); - zend_vm_stack_destroy(); if (EG(full_tables_cleanup)) { From c45f19590c4d442c0ecf5a3b55cd0fb928243e6a Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 28 Aug 2019 15:35:53 +0200 Subject: [PATCH 2/2] Remove delref in free_object_storage This gives us better object leak diagnostics. --- Zend/zend_objects_API.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c index 7c5d44a502b..80359b5e1eb 100644 --- a/Zend/zend_objects_API.c +++ b/Zend/zend_objects_API.c @@ -87,7 +87,8 @@ ZEND_API void ZEND_FASTCALL zend_objects_store_free_object_storage(zend_objects_ return; } - /* Free object contents, but don't free objects themselves, so they show up as leaks */ + /* Free object contents, but don't free objects themselves, so they show up as leaks. + * Also add a ref to all objects, so the object can't be freed by something else later. */ end = objects->object_buckets + 1; obj_ptr = objects->object_buckets + objects->top; @@ -101,7 +102,6 @@ ZEND_API void ZEND_FASTCALL zend_objects_store_free_object_storage(zend_objects_ if (obj->handlers->free_obj != zend_object_std_dtor) { GC_ADDREF(obj); obj->handlers->free_obj(obj); - GC_DELREF(obj); } } } @@ -115,7 +115,6 @@ ZEND_API void ZEND_FASTCALL zend_objects_store_free_object_storage(zend_objects_ GC_ADD_FLAGS(obj, IS_OBJ_FREE_CALLED); GC_ADDREF(obj); obj->handlers->free_obj(obj); - GC_DELREF(obj); } } } while (obj_ptr != end);