Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions future.c
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,12 @@ static zend_object *async_future_state_transfer_obj(
zend_object *object, zend_async_thread_transfer_ctx_t *ctx,
zend_object_transfer_kind_t kind, zend_object_transfer_default_fn default_fn)
{
if (kind == ZEND_OBJECT_TRANSFER_RELEASE) {
/* The shell's shared_state ownership moves to the destination under the
* future protocol; reworking that is a change of its own. */
return NULL;
}

if (kind == ZEND_OBJECT_TRANSFER) {
/* Source thread: create shared_state, bind to original future */
async_future_state_t *src = FUTURE_STATE_FROM_OBJ(object);
Expand Down
21 changes: 21 additions & 0 deletions thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,21 @@ static void thread_release_transferred_object(thread_release_ctx_t *ctx, zend_ob
obj->properties = NULL;
}

/* Whatever TRANSFER put in the C prefix of this shell is reachable only
* through the class: free_obj never runs for a shell. Resolved by name
* without autoload — a release runs outside a request. */
zend_string *lookup_name = zend_string_init(
ZSTR_VAL(class_name), ZSTR_LEN(class_name), 0);
zend_class_entry *ce = zend_lookup_class_ex(
lookup_name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
zend_string_release(lookup_name);

if (ce != NULL && ce->default_object_handlers != NULL
&& ce->default_object_handlers->transfer_obj != NULL) {
ce->default_object_handlers->transfer_obj(
obj, NULL, ZEND_OBJECT_TRANSFER_RELEASE, NULL);
}

for (uint32_t i = 0; i < prop_count; i++) {
thread_release_transferred_zval(ctx, &obj->properties_table[i]);
}
Expand Down Expand Up @@ -3279,6 +3294,12 @@ static zend_object *closure_transfer_obj(
zend_object *object, zend_async_thread_transfer_ctx_t *ctx,
zend_object_transfer_kind_t kind, zend_object_transfer_default_fn default_fn)
{
if (kind == ZEND_OBJECT_TRANSFER_RELEASE) {
/* The snapshot is freed by thread_release_transferred_object, which
* recognises a closure shell by its non-NULL `properties`. */
return NULL;
}

if (kind == ZEND_OBJECT_TRANSFER) {
/* Source thread → persistent: deep-copy closure via snapshot */
const zend_function *func = zend_get_closure_method_def(object);
Expand Down
6 changes: 6 additions & 0 deletions thread_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,12 @@ static zend_object *async_thread_channel_transfer_obj(
zend_object *object, zend_async_thread_transfer_ctx_t *ctx,
zend_object_transfer_kind_t kind, zend_object_transfer_default_fn default_fn)
{
if (kind == ZEND_OBJECT_TRANSFER_RELEASE) {
/* The shell's channel reference outlives it; dropping one needs the
* channel's event dispose protocol, which is a change of its own. */
return NULL;
}

if (kind == ZEND_OBJECT_TRANSFER) {
/* Transfer: pemalloc wrapper via default, then copy channel pointer */
zend_object *dst = default_fn(object, ctx, sizeof(thread_channel_object_t));
Expand Down
Loading