diff --git a/NEWS b/NEWS index 584064078a0..9c97a52402a 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ PHP NEWS . Fixed bug GH-19934 (CGI with auto_globals_jit=0 causes uouv). (ilutov) . Fixed bug GH-20073 (Assertion failure in WeakMap offset operations on reference). (nielsdos) + . Fixed bug GH-19844 (Don't bail when closing resources on shutdown). (ilutov) - DOM: . Partially fixed bug GH-16317 (DOM classes do not allow diff --git a/Zend/tests/gh19844.phpt b/Zend/tests/gh19844.phpt new file mode 100644 index 00000000000..29786407353 --- /dev/null +++ b/Zend/tests/gh19844.phpt @@ -0,0 +1,46 @@ +--TEST-- +GH-19844: Bail from stream_close() in zend_shutdown_executor_values() +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Fatal error: Bail in %s on line %d + +Fatal error: Bail in %s on line %d + +Fatal error: Bail in %s on line %d diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index d4a373616fe..e2503d6d304 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -274,9 +274,7 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown) zval *zv; EG(flags) |= EG_FLAGS_IN_RESOURCE_SHUTDOWN; - zend_try { - zend_close_rsrc_list(&EG(regular_list)); - } zend_end_try(); + zend_close_rsrc_list(&EG(regular_list)); /* No PHP callback functions should be called after this point. */ EG(active) = 0; diff --git a/Zend/zend_list.c b/Zend/zend_list.c index bf599a2efca..5add19256a6 100644 --- a/Zend/zend_list.c +++ b/Zend/zend_list.c @@ -217,15 +217,25 @@ void zend_close_rsrc_list(HashTable *ht) /* Reload ht->arData on each iteration, as it may be reallocated. */ uint32_t i = ht->nNumUsed; - while (i-- > 0) { - zval *p = ZEND_HASH_ELEMENT(ht, i); - if (Z_TYPE_P(p) != IS_UNDEF) { - zend_resource *res = Z_PTR_P(p); - if (res->type >= 0) { - zend_resource_dtor(res); +retry: + zend_try { + while (i-- > 0) { + zval *p = ZEND_HASH_ELEMENT(ht, i); + if (Z_TYPE_P(p) != IS_UNDEF) { + zend_resource *res = Z_PTR_P(p); + if (res->type >= 0) { + zend_resource_dtor(res); + } } } - } + } zend_catch { + /* If we have bailed, we probably executed user code (e.g. user stream + * API). Keep closing resources so they don't leak. User handlers must be + * called now so they aren't called in zend_deactivate() on + * zend_destroy_rsrc_list(&EG(regular_list)). At that point, the executor + * has already shut down and the process would crash. */ + goto retry; + } zend_end_try(); }