Skip to content

Commit 25dd603

Browse files
committed
Fix coroutine queue/array consistency: ensure coroutine is added to ASYNC_G(coroutines) immediately after enqueue
Move the addition of coroutine to ASYNC_G(coroutines) hash table to occur immediately after adding to the coroutine_queue, before any callback invocations that might throw exceptions. This prevents a critical race condition where: 1. Coroutine is added to coroutine_queue (line 154-158) 2. Exception occurs in after_coroutine_enqueue or afterCoroutineEnqueue callbacks 3. Function returns NULL without adding coroutine to ASYNC_G(coroutines) 4. Scheduler later extracts coroutine from queue and tries to execute it 5. async_coroutine_execute() fails trying to remove non-existent entry from ASYNC_G(coroutines) Changes: - Move zend_hash_index_add_ptr() call from line 193 to line 166 - Move ZEND_ASYNC_INCREASE_COROUTINE_COUNT from line 199 to line 172 - Ensures atomicity: if coroutine is in queue, it's also in the hash table - Callback errors now occur after coroutine is properly registered in both structures This guarantees consistency between ASYNC_G(coroutine_queue) and ASYNC_G(coroutines).
1 parent bd485bd commit 25dd603

File tree

1 file changed

+8
-8
lines changed

1 file changed

+8
-8
lines changed

async_API.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,14 @@ zend_coroutine_t *spawn(zend_async_scope_t *scope, zend_object *scope_provider,
163163
return NULL;
164164
}
165165

166+
if (UNEXPECTED(zend_hash_index_add_ptr(&ASYNC_G(coroutines), coroutine->std.handle, coroutine) == NULL)) {
167+
waker->status = ZEND_ASYNC_WAKER_IGNORED;
168+
async_throw_error("Failed to add coroutine to the list");
169+
return NULL;
170+
}
171+
172+
ZEND_ASYNC_INCREASE_COROUTINE_COUNT;
173+
166174
scope->after_coroutine_enqueue(&coroutine->coroutine, scope);
167175
if (UNEXPECTED(EG(exception))) {
168176
waker->status = ZEND_ASYNC_WAKER_IGNORED;
@@ -190,14 +198,6 @@ zend_coroutine_t *spawn(zend_async_scope_t *scope, zend_object *scope_provider,
190198
zval_ptr_dtor(&options);
191199
}
192200

193-
if (UNEXPECTED(zend_hash_index_add_ptr(&ASYNC_G(coroutines), coroutine->std.handle, coroutine) == NULL)) {
194-
waker->status = ZEND_ASYNC_WAKER_IGNORED;
195-
async_throw_error("Failed to add coroutine to the list");
196-
return NULL;
197-
}
198-
199-
ZEND_ASYNC_INCREASE_COROUTINE_COUNT;
200-
201201
return &coroutine->coroutine;
202202
}
203203

0 commit comments

Comments
 (0)