php / php/php-src

Built-in server leaks a file descriptor on every HEAD request for a static file

Open Beginner friendly
#23,764 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug SAPI: cli_server Status: Verified
Dominant language
C
Stars
40.4k
Forks
8.1k
Avg merge
2d 13h
Merged PRs (30d)
96

Description

Description

Since PHP 8.2 (#8215), php_cli_server_begin_send_static() in sapi/cli/php_cli_server.c opens the static file but only stores the descriptor in client->file_fd for non-HEAD requests:

fd = open(client->request.path_translated, O_RDONLY);
...
if (client->request.request_method != PHP_HTTP_HEAD) {
    client->file_fd = fd;
}

For HEAD, fd is never stored and never closed. Each HEAD request to a static file leaks one descriptor; once RLIMIT_NOFILE is reached every request fails with 404 ... Too many open files. A monitoring probe doing HEAD / every 40 s takes down php -S in ~11 hours.

Affected: PHP-8.2, PHP-8.3, PHP-8.4, PHP-8.5, master. PHP 8.1 is not affected (no HEAD special-casing).

Reproduction:

mkdir t && echo hi > t/index.html
php -S 127.0.0.1:8080 -t t &
for i in $(seq 100); do curl -sI http://127.0.0.1:8080/ >/dev/null; done
ls -l /proc/$!/fd | grep -c index.html   # 100

Suggested fix — close the descriptor when it is not handed to the content sender (Content-Length uses client->request.sb.st_size from the earlier stat, so the fd is not needed for HEAD at all):

if (client->request.request_method != PHP_HTTP_HEAD) {
    client->file_fd = fd;
} else {
    close(fd);
}
PHP Version

PHP 8.2 – 8.5, master

Operating System

Linux (any)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in sapi/cli/php_cli_server.c at php_cli_server_begin_send_static(), then run the provided php -S and repeated curl HEAD reproduction. Done means repeated HEAD requests to a static file no longer increase open file descriptors, while normal static responses continue to work.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, php
Domain
cli, networking
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.