diff --git a/frankenphp.c b/frankenphp.c index cebdcd2952..d57e4de162 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -178,6 +178,10 @@ static void *frankenphp_parent_death_watcher(void *arg) { #endif static void frankenphp_fork_child(void) { + // a fork of a fork (e.g. a daemonizer) must outlive its short-lived parent + if (is_forked_child) { + return; + } frankenphp_mark_fork_child(); #if defined(__linux__) // if the parent process dies between fork() and this prctl() diff --git a/frankenphp_test.go b/frankenphp_test.go index ef47fff4c9..b8988cbf0f 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -508,6 +508,24 @@ func testPhpInfoForkChild(t *testing.T, opts *testOptions) { }, opts) } +func TestDoubleForkGrandchild_module(t *testing.T) { testDoubleForkGrandchild(t, nil) } +func TestDoubleForkGrandchild_worker(t *testing.T) { + testDoubleForkGrandchild(t, &testOptions{workerScript: "double-fork.php"}) +} +func testDoubleForkGrandchild(t *testing.T, opts *testOptions) { + if opts == nil { + opts = &testOptions{} + } + opts.nbParallelRequests = 1 + runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, _ int) { + body, _ := testGet("http://example.com/double-fork.php", handler, t) + if body == "pcntl-unavailable" { + t.Skip("pcntl/posix not fully loaded") + } + require.Equal(t, "grandchild-alive", body) + }, opts) +} + func TestPersistentObject_module(t *testing.T) { testPersistentObject(t, nil) } func TestPersistentObject_worker(t *testing.T) { testPersistentObject(t, &testOptions{workerScript: "persistent-object.php"}) diff --git a/testdata/double-fork.php b/testdata/double-fork.php new file mode 100644 index 0000000000..1c4a4fd1b3 --- /dev/null +++ b/testdata/double-fork.php @@ -0,0 +1,43 @@ +