From 6b3408c26b915ccd6118f50b0c0dbd39a9e3e4e0 Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 6 Apr 2026 19:24:05 +0700 Subject: [PATCH 1/5] fix dead forked pthread_fork children --- frankenphp.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/frankenphp.c b/frankenphp.c index 7f396989a0..87a93ee1b6 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -87,6 +87,11 @@ __thread uintptr_t thread_index; __thread bool is_worker_thread = false; __thread HashTable *sandboxed_env = NULL; +#ifndef PHP_WIN32 +static bool is_forked_child = false; +static void frankenphp_fork_child(void) { is_forked_child = true; } +#endif + void frankenphp_update_local_thread_context(bool is_worker) { is_worker_thread = is_worker; @@ -601,6 +606,12 @@ PHP_FUNCTION(frankenphp_handle_request) { } } +#ifndef PHP_WIN32 + if (is_forked_child) { + _exit(0); + } +#endif + frankenphp_worker_request_shutdown(); go_frankenphp_finish_worker_request(thread_index, callback_ret); if (result.r1 != NULL) { @@ -699,6 +710,9 @@ PHP_FUNCTION(frankenphp_log) { PHP_MINIT_FUNCTION(frankenphp) { register_frankenphp_symbols(module_number); +#ifndef PHP_WIN32 + pthread_atfork(NULL, NULL, frankenphp_fork_child); +#endif zend_function *func; @@ -1086,6 +1100,11 @@ static void *php_thread(void *arg) { /* Execute the PHP script, potential bailout to zend_catch */ php_execute_script(&file_handle); +#ifndef PHP_WIN32 + if (is_forked_child) { + _exit(EG(exit_status)); + } +#endif zend_destroy_file_handle(&file_handle); reset_sandboxed_environment(); @@ -1102,6 +1121,12 @@ static void *php_thread(void *arg) { } } zend_catch { +#ifndef PHP_WIN32 + if (is_forked_child) { + _exit(EG(exit_status)); + } +#endif + /* Critical failure from php_execute_script or php_request_shutdown, mark * the thread as unhealthy */ thread_is_healthy = false; From 5aff0c9cdd2142ee5672ac9e80c0c2a248352f5d Mon Sep 17 00:00:00 2001 From: henderkes Date: Mon, 6 Apr 2026 21:31:51 +0700 Subject: [PATCH 2/5] force exit after php shutdown/cleanup ran --- frankenphp.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/frankenphp.c b/frankenphp.c index 87a93ee1b6..8dccd9af68 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -606,13 +606,12 @@ PHP_FUNCTION(frankenphp_handle_request) { } } + frankenphp_worker_request_shutdown(); #ifndef PHP_WIN32 if (is_forked_child) { _exit(0); } #endif - - frankenphp_worker_request_shutdown(); go_frankenphp_finish_worker_request(thread_index, callback_ret); if (result.r1 != NULL) { zval_ptr_dtor(result.r1); @@ -1100,11 +1099,6 @@ static void *php_thread(void *arg) { /* Execute the PHP script, potential bailout to zend_catch */ php_execute_script(&file_handle); -#ifndef PHP_WIN32 - if (is_forked_child) { - _exit(EG(exit_status)); - } -#endif zend_destroy_file_handle(&file_handle); reset_sandboxed_environment(); @@ -1117,16 +1111,15 @@ static void *php_thread(void *arg) { /* shutdown the request, potential bailout to zend_catch */ php_request_shutdown((void *)0); frankenphp_free_request_context(); +#ifndef PHP_WIN32 + if (is_forked_child) { + _exit(EG(exit_status)); + } +#endif go_frankenphp_after_script_execution(thread_index, EG(exit_status)); } } zend_catch { -#ifndef PHP_WIN32 - if (is_forked_child) { - _exit(EG(exit_status)); - } -#endif - /* Critical failure from php_execute_script or php_request_shutdown, mark * the thread as unhealthy */ thread_is_healthy = false; @@ -1146,6 +1139,11 @@ static void *php_thread(void *arg) { PG(last_error_file) = NULL; } frankenphp_free_request_context(); +#ifndef PHP_WIN32 + if (is_forked_child) { + _exit(EG(exit_status)); + } +#endif go_frankenphp_after_script_execution(thread_index, EG(exit_status)); } zend_end_try(); From 679a48e5f11215e898eb47171e33ad47a0b85df2 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 11 Apr 2026 15:35:11 +0700 Subject: [PATCH 3/5] Revert "force exit after php shutdown/cleanup ran" This reverts commit 5aff0c9cdd2142ee5672ac9e80c0c2a248352f5d. --- frankenphp.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/frankenphp.c b/frankenphp.c index 8dccd9af68..87a93ee1b6 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -606,12 +606,13 @@ PHP_FUNCTION(frankenphp_handle_request) { } } - frankenphp_worker_request_shutdown(); #ifndef PHP_WIN32 if (is_forked_child) { _exit(0); } #endif + + frankenphp_worker_request_shutdown(); go_frankenphp_finish_worker_request(thread_index, callback_ret); if (result.r1 != NULL) { zval_ptr_dtor(result.r1); @@ -1099,6 +1100,11 @@ static void *php_thread(void *arg) { /* Execute the PHP script, potential bailout to zend_catch */ php_execute_script(&file_handle); +#ifndef PHP_WIN32 + if (is_forked_child) { + _exit(EG(exit_status)); + } +#endif zend_destroy_file_handle(&file_handle); reset_sandboxed_environment(); @@ -1111,15 +1117,16 @@ static void *php_thread(void *arg) { /* shutdown the request, potential bailout to zend_catch */ php_request_shutdown((void *)0); frankenphp_free_request_context(); -#ifndef PHP_WIN32 - if (is_forked_child) { - _exit(EG(exit_status)); - } -#endif go_frankenphp_after_script_execution(thread_index, EG(exit_status)); } } zend_catch { +#ifndef PHP_WIN32 + if (is_forked_child) { + _exit(EG(exit_status)); + } +#endif + /* Critical failure from php_execute_script or php_request_shutdown, mark * the thread as unhealthy */ thread_is_healthy = false; @@ -1139,11 +1146,6 @@ static void *php_thread(void *arg) { PG(last_error_file) = NULL; } frankenphp_free_request_context(); -#ifndef PHP_WIN32 - if (is_forked_child) { - _exit(EG(exit_status)); - } -#endif go_frankenphp_after_script_execution(thread_index, EG(exit_status)); } zend_end_try(); From 1c49d32937b2cc7987b48c35e759f07ec3831a83 Mon Sep 17 00:00:00 2001 From: Marc Date: Mon, 13 Apr 2026 01:14:35 +0700 Subject: [PATCH 4/5] Apply suggestions from code review certainly shouldn't cause any side effects since the only way this code path is hit is if something calls `pcntl_fork` (or an extension forks). Co-authored-by: Alexander Stecher <45872305+AlliBalliBaba@users.noreply.github.com> Signed-off-by: Marc --- frankenphp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frankenphp.c b/frankenphp.c index 87a93ee1b6..bcf379815c 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -1101,7 +1101,7 @@ static void *php_thread(void *arg) { /* Execute the PHP script, potential bailout to zend_catch */ php_execute_script(&file_handle); #ifndef PHP_WIN32 - if (is_forked_child) { + if (UNEXPECTED(is_forked_child)) { _exit(EG(exit_status)); } #endif @@ -1122,7 +1122,7 @@ static void *php_thread(void *arg) { } zend_catch { #ifndef PHP_WIN32 - if (is_forked_child) { + if (UNEXPECTED(is_forked_child)) { _exit(EG(exit_status)); } #endif From 875dc394a7aa27c6564ec7c81e616f2e0d97b7b7 Mon Sep 17 00:00:00 2001 From: Marc Date: Mon, 13 Apr 2026 01:51:33 +0700 Subject: [PATCH 5/5] Update frankenphp.c Co-authored-by: Alexander Stecher <45872305+AlliBalliBaba@users.noreply.github.com> Signed-off-by: Marc --- frankenphp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frankenphp.c b/frankenphp.c index bcf379815c..df6358e233 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -607,7 +607,7 @@ PHP_FUNCTION(frankenphp_handle_request) { } #ifndef PHP_WIN32 - if (is_forked_child) { + if (UNEXPECTED(is_forked_child)) { _exit(0); } #endif