8000 Fix GH-10496: Segfault in fiber with nested calls · bwoebi/php-src@37cb645 · GitHub
[go: up one dir, main page]

8000
Skip to content

Commit 37cb645

Browse files
committed
Fix phpGH-10496: Segfault in fiber with nested calls
1 parent fe2dc2b commit 37cb645

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

Zend/tests/fibers/gh10496.phpt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--FILE--
2+
Segfault when garbage collector is invoked inside of fiber
3+
--TEST--
4+
<?php
5+
6+
function x(&$ref) {
7+
$ref = new class() {
8+
function __destruct() {
9+
print "Dtor x()\n";
10+
}
11+
};
12+
}
13+
function suspend($x) {
14+
Fiber::suspend();
15+
}
16+
$f = new Fiber(function() use (&$f) {
17+
try {
18+
x($var);
19+
\ord(suspend(1));
20+
} finally {
21+
print "Cleaned\n";
22+
}
23+
});
24+
$f->start();
25+
unset($f);
26+
gc_collect_cycles();
27+
print "Collected\n";
28+
29+
?>
30+
--EXPECT--
31+
Cleaned
32+
Dtor x()
33+
Collected

Zend/zend_execute.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4116,6 +4116,8 @@ static zend_always_inline zend_generator *zend_get_running_generator(EXECUTE_DAT
41164116

41174117
ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_execute_data *call, uint32_t op_num, zend_get_gc_buffer *buf) /* {{{ */
41184118
{
4119+
bool skip_current_call = (EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) == 0 || (((zend_generator *) EX(return_value))->flags & ZEND_GENERATOR_IN_FIBER) != 0;
4120+
41194121
zend_op *opline = EX(func)->op_array.opcodes + op_num;
41204122
int level;
41214123
int do_exit;
@@ -4131,6 +4133,7 @@ ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_exe
41314133
opline->opcode == ZEND_NEW)) {
41324134
ZEND_ASSERT(op_num);
41334135
opline--;
4136+
skip_current_call = false;
41344137
}
41354138

41364139
do {
@@ -4189,7 +4192,7 @@ ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_exe
41894192
opline--;
41904193
}
41914194
} while (!do_exit);
4192-
if (call->prev_execute_data) {
4195+
if (skip_current_call || call->prev_execute_data) {
41934196
/* skip current call region */
41944197
level = 0;
41954198
do_exit = 0;
@@ -4219,6 +4222,11 @@ ZEND_API void zend_unfinished_calls_gc(zend_execute_data *execute_data, zend_exe
42194222
} while (!do_exit);
42204223
}
42214224

4225+
if (skip_current_call) {
4226+
skip_current_call = false;
4227+
continue;
4228+
}
4229+
42224230
if (EXPECTED(num_args > 0)) {
42234231
zval *p = ZEND_CALL_ARG(call, 1);
42244232
do {

0 commit comments

Comments
 (0)
0