Skip to content

Commit c5003a7

Browse files
committed
Merge branch 'PHP-8.6'
* PHP-8.6: Fix GH-24046: FPM worker stdio pipe fd closed twice # Conflicts: # NEWS
2 parents af19251 + 1471453 commit c5003a7

2 files changed

Lines changed: 65 additions & 0 deletions

File tree

‎sapi/fpm/fpm/fpm_children.c‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,11 @@ static void fpm_child_close(struct fpm_child_s *child, int in_event_loop) /* {{{
8787
fpm_event_fire(&child->ev_stdout);
8888
}
8989
if (child->fd_stdout != -1) {
90+
if (in_event_loop) {
91+
fpm_event_del(&child->ev_stdout);
92+
}
9093
close(child->fd_stdout);
94+
child->fd_stdout = -1;
9195
}
9296
}
9397

@@ -97,7 +101,11 @@ static void fpm_child_close(struct fpm_child_s *child, int in_event_loop) /* {{{
97101
fpm_event_fire(&child->ev_stderr);
98102
}
99103
if (child->fd_stderr != -1) {
104+
if (in_event_loop) {
105+
fpm_event_del(&child->ev_stderr);
106+
}
100107
close(child->fd_stderr);
108+
child->fd_stderr = -1;
101109
}
102110
}
103111

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--TEST--
2+
GH-24046 (FPM: worker stdio pipe fd closed twice when a child process outlives the worker)
3+
--SKIPIF--
4+
<?php include "skipif.inc"; ?>
5+
--FILE--
6+
<?php
7+
8+
require_once "tester.inc";
9+
10+
$cfg = <<<EOT
11+
[global]
12+
error_log = {{FILE:LOG}}
13+
[unconfined]
14+
listen = {{ADDR}}
15+
pm = static
16+
pm.max_children = 1
17+
pm.max_requests = 1
18+
catch_workers_output = yes
19+
decorate_workers_output = no
20+
EOT;
21+
22+
$code = <<<'EOT'
23+
<?php
24+
/* dup() of the worker's stderr pipe that is inherited by the background process */
25+
$stderr = fopen('php://stderr', 'a');
26+
if (@fwrite($stderr, "log line\n") === false) {
27+
echo "write to stderr failed";
28+
exit;
29+
}
30+
if (isset($_GET['bg'])) {
31+
exec('sleep 3 > /dev/null 2>&1 &');
32+
}
33+
echo "ok";
34+
EOT;
35+
36+
$tester = new FPM\Tester($cfg, $code);
37+
$tester->start();
38+
$tester->expectLogStartNotices();
39+
/* The worker exits after this request while the background process still holds
40+
* its stderr pipe open. The replacement worker gets the same pipe fd numbers. */
41+
$tester->request('bg=1')->expectBody('ok');
42+
/* Wait for the postponed free of the exited worker. */
43+
usleep(1500000);
44+
$tester->request()->expectBody('ok');
45+
$tester->terminate();
46+
$tester->expectNoLogPattern('/unable to (remove|read)/');
47+
$tester->close();
48+
49+
?>
50+
Done
51+
--EXPECT--
52+
Done
53+
--CLEAN--
54+
<?php
55+
require_once "tester.inc";
56+
FPM\Tester::clean();
57+
?>

0 commit comments

Comments
 (0)