Skip to content

Commit f441305

Browse files
committed
Zend: Fix leaks when destructors throw during shutdown
1 parent e88e049 commit f441305

4 files changed

Lines changed: 36 additions & 2 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ PHP NEWS
3636
. Fixed bug GH-21603 (Missing addref for __unset). (ilutov)
3737
. Fixed bug GH-21760 (Trait with class constant name conflict against
3838
enum case causes SEGV). (Pratik Bhujel)
39+
. Fixed GH-22010 (Exception thrown in destructor during shutdown causes a
40+
memory leak). (Weilin Du)
3941

4042
- CLI:
4143
. Fixed bug GH-21754 (`--rf` command line option with a method triggers

Zend/tests/gh22010.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
GH-22010: Exception thrown in destructor during shutdown
3+
--FILE--
4+
<?php
5+
6+
class A
7+
{
8+
public function __destruct()
9+
{
10+
throw new Exception(__METHOD__);
11+
}
12+
}
13+
14+
$a = new A;
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Uncaught Exception: A::__destruct in %s:%d
19+
Stack trace:
20+
#0 [internal function]: A->__destruct()
21+
#1 {main}
22+
thrown in %s on line %d

Zend/zend_objects.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,12 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
193193
}
194194
}
195195

196-
zend_call_known_instance_method_with_0_params(destructor, object, NULL);
196+
zend_try {
197+
zend_call_known_instance_method_with_0_params(destructor, object, NULL);
198+
} zend_catch {
199+
OBJ_RELEASE(object);
200+
zend_bailout();
201+
} zend_end_try();
197202

198203
if (old_exception) {
199204
if (EG(current_execute_data)) {

Zend/zend_objects_API.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ ZEND_API void ZEND_FASTCALL zend_objects_store_call_destructors(zend_objects_sto
5454
if (obj->handlers->dtor_obj != zend_objects_destroy_object
5555
|| obj->ce->destructor) {
5656
GC_ADDREF(obj);
57-
obj->handlers->dtor_obj(obj);
57+
zend_try {
58+
obj->handlers->dtor_obj(obj);
59+
} zend_catch {
60+
GC_DELREF(obj);
61+
zend_bailout();
62+
} zend_end_try();
5863
GC_DELREF(obj);
5964
}
6065
}

0 commit comments

Comments
 (0)