Skip to content

Commit 3f3e641

Browse files
committed
zend_async_API: honor the NULL-coroutine contract in context_destroy, lock key_name
zend_async_context_destroy is documented with its siblings as resolving a NULL coroutine to the current one but dereferenced the argument directly. zend_async_internal_context_key_name read the process-wide key registry without the mutex every writer takes, racing a concurrent rehash.
1 parent 2ada86e commit 3f3e641

1 file changed

Lines changed: 16 additions & 1 deletion

File tree

Zend/zend_async_API.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,18 @@ ZEND_API uint32_t zend_async_internal_context_key_alloc(const char *key_name)
112112

113113
ZEND_API const char *zend_async_internal_context_key_name(uint32_t key)
114114
{
115+
/* A non-NULL table implies the mutex exists: key_alloc creates the mutex
116+
* before the table. The lock shields the read from a concurrent alloc
117+
* rehashing the bucket array. */
115118
if (internal_context_key_names == NULL) {
116119
return NULL;
117120
}
118121

119-
return zend_hash_index_find_ptr(internal_context_key_names, key);
122+
tsrm_mutex_lock(internal_context_mutex);
123+
const char *name = zend_hash_index_find_ptr(internal_context_key_names, key);
124+
tsrm_mutex_unlock(internal_context_mutex);
125+
126+
return name;
120127
}
121128

122129
static void internal_context_keys_shutdown(void)
@@ -383,6 +390,14 @@ ZEND_API bool zend_async_context_unset(zend_coroutine_t *coroutine, zval *key)
383390

384391
ZEND_API void zend_async_context_destroy(zend_coroutine_t *coroutine)
385392
{
393+
if (coroutine == NULL) {
394+
coroutine = ZEND_ASYNC_CURRENT_COROUTINE;
395+
396+
if (coroutine == NULL) {
397+
return;
398+
}
399+
}
400+
386401
if (coroutine->context != NULL) {
387402
OBJ_RELEASE(coroutine->context);
388403
coroutine->context = NULL;

0 commit comments

Comments
 (0)