[php-src] PR #24541: Fix FPM truncating output of 2 GiB or more

From: Date: Thu, 22 Oct 2026 14:23:20 +0000
Subject: [php-src] PR #24541: Fix FPM truncating output of 2 GiB or more
Groups: php.git-pulls 
Request: Send a blank email to git-pulls+get-39705@lists.php.net to get a copy of this message
Pull Request: https://github.com/php/php-src/pull/24541 Author: Marti2203 In FPM, sapi_cgibin_ub_write() stores the remaining length in a uint32_t, and sapi_cgibin_single_write() passes it on to fcgi_write(), which takes an int: ```c static size_t sapi_cgibin_ub_write(const char *str, size_t str_length) { uint32_t remaining = str_length; ... ret = sapi_cgibin_single_write(ptr, remaining); /* -> fcgi_write(..., int len) */ ``` A single write of 2 GiB or more is therefore sent truncated or not at all: - From 2 GiB to just under 4 GiB, the length becomes negative as an int. fcgi_write() returns 0, sapi_cgibin_ub_write() treats that as an aborted connection, and no body is sent. - At 4 GiB or more, only the low 32 bits of the length are written. In both cases the request ends normally (END_REQUEST with status 0) and nothing is logged, so the client just gets a short response. This happens for any script that echoes a single string of that size with output buffering off, or when the output buffer is flushed with that much data in it. The CGI SAPI already handles this: sapi_fcgi_ub_write() in sapi/cgi/cgi_main.c uses size_t remaining and caps each fcgi_write() call at INT_MAX. ### Reproducer big.php: ```php <?php echo str_repeat('A', (int)$_GET['n']); ``` The pool runs with pm = static, pm.max_children = 1, php_admin_value[memory_limit] = -1 and php_admin_value[output_buffering] = 0. A small FastCGI client sends GET big.php?n=... and counts the FCGI_STDOUT bytes (the 72 header bytes are not counted below). | n | body bytes before | body bytes after | |---|---|---| | 104857600 (100 MiB) | 104857600 | 104857600 | | 3221225472 (3 GiB) | 0 | 3221225472 | | 4294967306 (4 GiB + 10) | 10 | 4294967306 | ### Fix Make the remaining length and the sapi_cgibin_single_write() parameter size_t, and cap each fcgi_write() call at INT_MAX, as cgi_main.c does. fcgi_write() and main/fastcgi.h are unchanged, so the CGI SAPI is not affected. The other fcgi_write() caller in FPM (sapi_cgi_log_fastcgi()) writes log messages and is left alone. ### Test sapi/fpm/tests/fcgi-write-over-4gib.phpt echoes 4 GiB + 10 bytes through FPM and checks the body length. This needs about 4 GB of memory in each of the FPM worker and the test client, so like the other large-memory tests it only runs with RUN_RESOURCE_HEAVY_TESTS set, on 64-bit platforms, and not with SKIP_SLOW_TESTS. - Without the fix: fails with int(10) instead of int(4294967306). - With the fix: passes (about 17 s); without RUN_RESOURCE_HEAVY_TESTS it is skipped. - sapi/fpm/tests: 118 passed, 18 skipped, 1 warned. Two tests failed (bug68423-multi-pool-all-pms.phpt and bug68391-conf-include-order.phpt) because another process on my shared test machine was already using ports 9010-9019. The failures are bind(): Address already in use and are unrelated to this change. This issue was found by an LLM-Enhanced Static Analysis Engine and verified manually. 🤖 Generated with [Claude Code](https://claude.com/claude-code)

« previous php.git-pulls (#39705) next »