Skip to content

Commit 03642bf

Browse files
committed
Fix coroutine scope tracking race condition
Move scope reference assignment from async_new_coroutine() to scope_before_coroutine_enqueue() to ensure coroutines are added to scope->coroutines array before scope is set. This prevents crashes when coroutines finish between creation and enqueue. Fixes assertion failures: "Scope should be empty before disposal"
1 parent e5280c6 commit 03642bf

File tree

2 files changed

+11
-16
lines changed

2 files changed

+11
-16
lines changed

coroutine.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -338,15 +338,17 @@ zend_coroutine_t *async_new_coroutine(zend_async_scope_t *scope)
338338

339339
async_coroutine_t *coroutine = (async_coroutine_t *) ZEND_ASYNC_OBJECT_TO_EVENT(object);
340340

341-
// Add the coroutine to the scope before calling the enqueue hook
342-
zval options;
343-
ZVAL_UNDEF(&options);
344-
if (!scope->before_coroutine_enqueue(&coroutine->coroutine, scope, &options)) {
341+
if (scope != NULL) {
342+
// Add the coroutine to the scope before calling the enqueue hook
343+
zval options;
344+
ZVAL_UNDEF(&options);
345+
if (!scope->before_coroutine_enqueue(&coroutine->coroutine, scope, &options)) {
346+
zval_ptr_dtor(&options);
347+
coroutine->coroutine.event.dispose(&coroutine->coroutine.event);
348+
return NULL;
349+
}
345350
zval_ptr_dtor(&options);
346-
coroutine->coroutine.event.dispose(&coroutine->coroutine.event);
347-
return NULL;
348351
}
349-
zval_ptr_dtor(&options);
350352

351353
return &coroutine->coroutine;
352354
}

scheduler.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -798,14 +798,6 @@ bool async_scheduler_launch(void)
798798
return false;
799799
}
800800

801-
zval options;
802-
ZVAL_UNDEF(&options);
803-
if (!scope->before_coroutine_enqueue(&main_coroutine->coroutine, scope, &options)) {
804-
zval_ptr_dtor(&options);
805-
return false;
806-
}
807-
zval_ptr_dtor(&options);
808-
809801
scope->after_coroutine_enqueue(&main_coroutine->coroutine, scope);
810802
if (UNEXPECTED(EG(exception) != NULL)) {
811803
return false;
@@ -876,6 +868,7 @@ bool async_scheduler_launch(void)
876868
return false;
877869
}
878870

871+
zval options;
879872
ZVAL_UNDEF(&options);
880873
if (!scope->before_coroutine_enqueue(scheduler_coroutine, scope, &options)) {
881874
zval_ptr_dtor(&options);
@@ -1035,7 +1028,7 @@ bool async_scheduler_coroutine_enqueue(zend_coroutine_t *coroutine)
10351028
if (UNEXPECTED(zend_hash_index_add_ptr(&ASYNC_G(coroutines), ((async_coroutine_t *)coroutine)->std.handle, coroutine) == NULL)) {
10361029
coroutine->waker->status = ZEND_ASYNC_WAKER_IGNORED;
10371030
async_throw_error("Failed to add coroutine to the list");
1038-
return NULL;
1031+
return false;
10391032
}
10401033

10411034
ZEND_ASYNC_INCREASE_COROUTINE_COUNT;

0 commit comments

Comments
 (0)