Skip to content

Commit 75ef3c7

Browse files
committed
Fix phpGH-10437: Segfault on suspending a dead fiber
1 parent ec23f28 commit 75ef3c7

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

Zend/tests/fibers/gh10437.phpt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-10437 (Segfault on suspending a dead fiber)
3+
--FILE--
4+
<?php
5+
6+
set_time_limit(1);
7+
8+
register_shutdown_function(function () {
9+
Fiber::getCurrent()->suspend();
10+
});
11+
12+
$fiber = new Fiber(function () {
13+
while (1);
14+
});
15+
$fiber->start();
16+
--EXPECTF--
17+
Fatal error: Maximum execution time of 1 second exceeded in %s
18+
19+
Fatal error: Uncaught FiberError: Cannot suspend a dead fiber in %s
20+
Stack trace:
21+
#0 %s: Fiber::suspend()
22+
#1 [internal function]: {closure}()
23+
#2 {main}
24+
thrown in %s

Zend/zend_fibers.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,26 @@ static HashTable *zend_fiber_object_gc(zend_object *object, zval **table, int *n
768768
return lastSymTable;
769769
}
770770

771+
static const char* zend_fiber_status_to_string(zend_fiber *fiber)
772+
{
773+
switch (fiber->context.status) {
774+
case ZEND_FIBER_STATUS_INIT:
775+
return "initializing";
776+
break;
777+
case ZEND_FIBER_STATUS_RUNNING:
778+
return "running";
779+
break;
780+
case ZEND_FIBER_STATUS_SUSPENDED:
781+
return "suspended";
782+
break;
783+
case ZEND_FIBER_STATUS_DEAD:
784+
return "dead";
785+
break;
786+
}
787+
788+
return "(unknown status)";
789+
}
790+
771791
ZEND_METHOD(Fiber, __construct)
772792
{
773793
zend_fcall_info fci;
@@ -846,7 +866,14 @@ ZEND_METHOD(Fiber, suspend)
846866
RETURN_THROWS();
847867
}
848868

849-
ZEND_ASSERT(fiber->context.status == ZEND_FIBER_STATUS_RUNNING || fiber->context.status == ZEND_FIBER_STATUS_SUSPENDED);
869+
if (UNEXPECTED(fiber->context.status != ZEND_FIBER_STATUS_RUNNING && fiber->context.status != ZEND_FIBER_STATUS_SUSPENDED)) {
870+
zend_throw_error(zend_ce_fiber_error,
871+
"Cannot suspend %s %s fiber",
872+
((fiber->context.status == ZEND_FIBER_STATUS_INIT) ? "an" : "a"),
873+
zend_fiber_status_to_string(fiber)
874+
);
875+
RETURN_THROWS();
876+
}
850877

851878
fiber->execute_data = EG(current_execute_data);
852879
fiber->stack_bottom->prev_execute_data = NULL;

0 commit comments

Comments
 (0)