Skip to content

Commit d679497

Browse files
committed
async: shutdown iterator dispose gives up on remaining destructors
The dispose of a destructor-pass iterator coroutine raised E_CORE_ERROR and then tried to re-run the pass - dead code, since a mid-request E_CORE_ERROR bails out and never returns. A scheduler may legitimately cancel the iterator (deadlock policy), so dying was wrong, and re-running destructors from dispose is unsafe (may be inside a bailout, user code forbidden). Follow the zend_catch policy instead: warn, reset the cursor, mark the remaining objects destructed.
1 parent 505d966 commit d679497

2 files changed

Lines changed: 9 additions & 6 deletions

File tree

Zend/zend_execute_API.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,11 @@ static void shutdown_destructors_coroutine_dtor(zend_coroutine_t *coroutine)
247247
if (EG(shutdown_context).coroutine == coroutine) {
248248
EG(shutdown_context).coroutine = NULL;
249249
EG(shutdown_context).pass = ZEND_SHUTDOWN_PASS_NONE;
250-
zend_error(E_CORE_ERROR, "Shutdown destructors coroutine was not finished properly");
250+
zend_error(E_WARNING, "Shutdown destructors coroutine was not finished properly");
251+
/* Dispose may run inside a bailout: no user code from here. Give up on
252+
* the remaining destructors the way the zend_catch below does. */
251253
EG(symbol_table).pDestructor = zend_unclean_zval_ptr_dtor;
252-
shutdown_destructors();
254+
zend_objects_store_mark_destructed(&EG(objects_store));
253255
}
254256
}
255257

Zend/zend_objects_API.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,16 @@ static void zend_objects_store_call_destructors_async_iterator_entry(void)
7171
}
7272

7373
/* Reset the shutdown cursor if the iterator coroutine is torn down mid-pass
74-
* (cancelled/errored) instead of finishing normally — otherwise is_started
75-
* stays true and every later call believes a pass is still in flight. */
74+
* (cancelled/errored) instead of finishing normally — otherwise the pass
75+
* stays marked in flight forever. Dispose may run inside a bailout: no user
76+
* code from here, the remaining destructors are given up. */
7677
static void zend_objects_store_call_destructors_async_coroutine_dtor(zend_coroutine_t *coroutine)
7778
{
7879
if (EG(shutdown_context).coroutine == coroutine) {
7980
EG(shutdown_context).coroutine = NULL;
8081
EG(shutdown_context).pass = ZEND_SHUTDOWN_PASS_NONE;
81-
zend_error(E_CORE_ERROR, "Object store destructors coroutine was not finished properly");
82-
shutdown_destructors();
82+
zend_error(E_WARNING, "Object store destructors coroutine was not finished properly");
83+
zend_objects_store_mark_destructed(&EG(objects_store));
8384
}
8485
}
8586

0 commit comments

Comments
 (0)