Skip to content

Commit e5280c6

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 29f050b commit e5280c6

File tree

2 files changed

+13
-10
lines changed

2 files changed

+13
-10
lines changed

async_API.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -106,18 +106,12 @@ zend_coroutine_t *spawn(zend_async_scope_t *scope, zend_object *scope_provider,
106106

107107
zend_apply_current_filename_and_line(&coroutine->coroutine.filename, &coroutine->coroutine.lineno);
108108

109-
zval options;
110-
ZVAL_UNDEF(&options);
111-
if (!scope->before_coroutine_enqueue(&coroutine->coroutine, scope, &options)) {
112-
zval_ptr_dtor(&options);
113-
coroutine->coroutine.event.dispose(&coroutine->coroutine.event);
114-
return NULL;
115-
}
116-
zval_ptr_dtor(&options);
117-
118109
const bool is_spawn_strategy =
119110
scope_provider != NULL && instanceof_function(scope_provider->ce, async_ce_spawn_strategy);
120111

112+
zval options;
113+
ZVAL_UNDEF(&options);
114+
121115
// call SpawnStrategy::beforeCoroutineEnqueue
122116
if (is_spawn_strategy) {
123117
zval coroutine_zval, scope_zval;

coroutine.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,16 @@ zend_coroutine_t *async_new_coroutine(zend_async_scope_t *scope)
337337
}
338338

339339
async_coroutine_t *coroutine = (async_coroutine_t *) ZEND_ASYNC_OBJECT_TO_EVENT(object);
340-
coroutine->coroutine.scope = scope;
340+
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)) {
345+
zval_ptr_dtor(&options);
346+
coroutine->coroutine.event.dispose(&coroutine->coroutine.event);
347+
return NULL;
348+
}
349+
zval_ptr_dtor(&options);
341350

342351
return &coroutine->coroutine;
343352
}

0 commit comments

Comments
 (0)