Skip to content
Open
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
25 changes: 24 additions & 1 deletion frankenphp.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,12 @@ __thread HashTable *sandboxed_env = NULL;

#ifndef PHP_WIN32
static bool is_forked_child = false;
static void frankenphp_fork_child(void) { is_forked_child = true; }
static void frankenphp_fork_child(void) {
is_forked_child = true;
#ifdef __linux__
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's an equivalent to this in macOS or BSD?

realistically speaking, it's hard to imagine this ever kicks in if a php object destructor waits on the child pid, but in case the php runtime throws an unrecoverable error in a destructor, it might exit the thread without calling the destructor responsible for signalling and cleaning up the child

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that this syscall can race. Here is a workaround: https://stackoverflow.com/a/59216119

On FreeBSD, you can do this:

#include <sys/procctl.h>
#include <signal.h>

int sig = SIGKILL;
// P_PID means we are targeting a process ID. 
// 0 means "the current calling process".
procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &sig);

On macOS, it's harder; you have to run kqueue and way more code.

#endif
}
#endif

/* Best-effort force-kill for stuck PHP threads.
Expand Down Expand Up @@ -916,6 +921,12 @@ static int frankenphp_startup(sapi_module_struct *sapi_module) {
static int frankenphp_deactivate(void) { return SUCCESS; }

static size_t frankenphp_ub_write(const char *str, size_t str_length) {
#ifndef PHP_WIN32
if (UNEXPECTED(is_forked_child)) {
return 0;
}
#endif

struct go_ub_write_return result =
go_ub_write(thread_index, (char *)str, str_length);

Expand All @@ -927,6 +938,12 @@ static size_t frankenphp_ub_write(const char *str, size_t str_length) {
}

static int frankenphp_send_headers(sapi_headers_struct *sapi_headers) {
#ifndef PHP_WIN32
if (UNEXPECTED(is_forked_child)) {
return SAPI_HEADER_SEND_FAILED;
}
#endif

if (SG(request_info).no_headers == 1) {
return SAPI_HEADER_SENT_SUCCESSFULLY;
}
Expand All @@ -952,6 +969,12 @@ static int frankenphp_send_headers(sapi_headers_struct *sapi_headers) {
}

static void frankenphp_sapi_flush(void *server_context) {
#ifndef PHP_WIN32
if (UNEXPECTED(is_forked_child)) {
return;
}
#endif

sapi_send_headers();
if (go_sapi_flush(thread_index)) {
php_handle_aborted_connection();
Expand Down