diff --git a/NEWS b/NEWS index c2767fd3c30c..a0becbde9965 100644 --- a/NEWS +++ b/NEWS @@ -36,6 +36,8 @@ PHP NEWS . Fixed bug GH-21603 (Missing addref for __unset). (ilutov) . Fixed bug GH-21760 (Trait with class constant name conflict against enum case causes SEGV). (Pratik Bhujel) + . Fixed GH-22010 (Exception thrown in destructor during shutdown causes a + memory leak). (Weilin Du) - CLI: . Fixed bug GH-21754 (`--rf` command line option with a method triggers diff --git a/Zend/tests/gh22010.phpt b/Zend/tests/gh22010.phpt new file mode 100644 index 000000000000..826949eba6b8 --- /dev/null +++ b/Zend/tests/gh22010.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-22010: Exception thrown in destructor during shutdown +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Exception: A::__destruct in %s:%d +Stack trace: +#0 [internal function]: A->__destruct() +#1 {main} + thrown in %s on line %d diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 8a54a8398691..56390efe6116 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -193,7 +193,12 @@ ZEND_API void zend_objects_destroy_object(zend_object *object) } } - zend_call_known_instance_method_with_0_params(destructor, object, NULL); + zend_try { + zend_call_known_instance_method_with_0_params(destructor, object, NULL); + } zend_catch { + OBJ_RELEASE(object); + zend_bailout(); + } zend_end_try(); if (old_exception) { if (EG(current_execute_data)) { diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c index c19873cf3be3..4eac6a8004dc 100644 --- a/Zend/zend_objects_API.c +++ b/Zend/zend_objects_API.c @@ -54,7 +54,12 @@ ZEND_API void ZEND_FASTCALL zend_objects_store_call_destructors(zend_objects_sto if (obj->handlers->dtor_obj != zend_objects_destroy_object || obj->ce->destructor) { GC_ADDREF(obj); - obj->handlers->dtor_obj(obj); + zend_try { + obj->handlers->dtor_obj(obj); + } zend_catch { + GC_DELREF(obj); + zend_bailout(); + } zend_end_try(); GC_DELREF(obj); } }