[php-src] Issue #24308: standard/syslog: the request shutdown hook calls closelog() even when the request never opened syslog
| From: | andypost | Date: | Tue, 13 Oct 2026 21:58:29 +0000 |
| Subject: | [php-src] Issue #24308: standard/syslog: the request shutdown hook calls closelog() even when the request never opened syslog | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-252990@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/24308
Author: andypost
### Description
ext/standard/syslog.c installs an unconditional request shutdown hook:
```c
PHP_RSHUTDOWN_FUNCTION(syslog)
{
php_closelog();
if (BG(syslog_device)) {
free(BG(syslog_device));
BG(syslog_device) = NULL;
}
return SUCCESS;
}
```
php_closelog() runs after every request, whether or not this request opened syslog. In
a SAPI that serves more than one request per process, that closes a process-wide handle the request
may not own, and the next request opens it again.
Note that the state to avoid this already exists: php_openlog() sets
PG(have_called_openlog) = 1 and php_closelog() clears it
(main/php_syslog.c:74-84), and php_module_startup() resets it to 0
(main/main.c:2317). The shutdown hook simply does not look at it.
### Expected
A request that never calls openlog(), closelog() or syslog()
should leave the process syslog handle alone. If the handle was opened outside PHP, for example by
the embedding application or by a library in the same process, PHP should not close it.
### Actual
Embedded SAPI, PHP 8.5.11 (Alpine 3.24.2, musl 1.2.6, OpenSSL 3.5.9), one worker process serving
three requests with error_log = syslog and a script that only calls
error_log("request"). strace of the worker:
```
1080 connect(15, {sa_family=AF_UNIX, sun_path="/dev/log"}, 12) = 0
1080 sendto(15, "<13>Oct 13 21:57:46 php: request\n", 33, 0, NULL, 0) = 33
1080 connect(14, {sa_family=AF_UNIX, sun_path="/dev/log"}, 12) = 0
1080 sendto(14, "<13>Oct 13 21:57:46 php: request\n", 33, 0, NULL, 0) = 33
1080 connect(14, {sa_family=AF_UNIX, sun_path="/dev/log"}, 12) = 0
1080 sendto(14, "<13>Oct 13 21:57:46 php: request\n", 33, 0, NULL, 0) = 33
```
Three requests, three connects: the handle does not survive a request boundary. In the same process,
a host that opened syslog before running PHP loses it when the first request ends. php-fpm works
around this by calling php_closelog() itself when it takes over the child, with the
comment "ensure to close syslog not to interrupt with PHP syslog code"
(sapi/fpm/fpm/fpm_stdio.c:144), which is the same interaction seen from the other side.
### Suggested fix
Check the existing flag before closing:
```c
PHP_RSHUTDOWN_FUNCTION(syslog)
{
if (PG(have_called_openlog)) {
php_closelog();
}
...
}
```
That keeps the per-request BG(syslog_device) cleanup, closes the handle when this
request opened it, and leaves a host-owned handle alone.
### Version
PHP 8.5.11, and the same code is in the current PHP-8.5 and master
branches.