[php-src] PR #24548: Fix GH-24492 (partial): route caller-sized string builders through the fallible allocator
| From: | VijhnAustin | Date: | Thu, 22 Oct 2026 15:26:22 +0000 |
| Subject: | [php-src] PR #24548: Fix GH-24492 (partial): route caller-sized string builders through the fallible allocator | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-39711@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/24548
Author: VijhnAustin
Fixes part of #24492.
## Problem
Several
ext/standard functions grow their output buffer with the non-fallible string
allocators. When the requested size crosses the soft memory_limit, the allocation is
not reported back to the caller; it escalates to the hard limit
(memory_hard_limit_percent) and the process is terminated via _exit(137),
so registered shutdown functions never run and the catchable "Allowed memory size …
exhausted" fatal that 8.5.11 produced for the same input is lost. A single userland call with
an attacker-influenced size is enough.
## Fix
Route these sites through the fallible allocation API already in the tree
(zend_string_fextend / zend_string_falloc /
zend_string_safe_falloc with fallible = true), propagate the
NULL, and surface the standard engine OOM via RETURN_OOM() at the userland
boundary:
-
sprintf/printf/vprintf/vsprintf/fprintf/vfprintf
(formatted_print.c; the php_sprintf_append* helpers now return
bool)
- pack (pack.c)
- bin2hex and utf8_encode (string.c)
- number_format (math.c; tmpbuf released on the failure path)
- convert_uuencode (uuencode.c)
- quoted_printable_encode (quot_print.c)
## Scope
This is a **partial** fix. Other sites named in the issue — base64_encode,
urlencode/rawurlencode, var_export, the bcmath family, and
the main/spprintf.c PAD_CHAR path — route their result through PHPAPI
helpers whose internal callers currently dereference the result without a NULL check (they never see
a failed huge allocation today because the process is killed first). Converting those safely needs a
caller audit, so they are intentionally left for follow-up. The ext/xml/Expat variant
is already handled in #24516.
## Reproduction
With memory_limit=16M and memory_hard_limit_percent=200:
```php
register_shutdown_function(static fn() => print("shutdown\n"));
sprintf("%40000000s", ""); // or pack("x40000000");
number_format(1.0, 100000000); etc.
```
Before (stock): Hard memory limit of 33554432 bytes exhausted …, exit 137, no
shutdown.
After (patched): catchable Allowed memory size of 16777216 bytes exhausted …,
shutdown runs, exit 255.
## Tests
Adds 17 .phpt under ext/standard/tests/{strings,math}/gh24492_*, each
pinning memory_hard_limit_percent=200 and asserting both the catchable fatal and that a
shutdown function still runs (so a failure while preparing the input cannot masquerade as a
reproduced bug). Verified on a Windows x64 build (17/17 passing); the patch applies cleanly to
current PHP-8.5. Also reproduces on 8.4.27 per the issue — happy to retarget to
PHP-8.4 if that is preferred.
🤖 Generated with [Claude Code](https://claude.com/claude-code)