forked from RoushTech/docker
frankenphp: give PHP threads a stack it can compile Twig on #30
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/frankenphp-zts-stack-size"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Ordinary Twig-heavy pages 500 on the FrankenPHP images with
Maximum call stack size of 83936 bytes ... reached during compilation.Cause
FrankenPHP creates the thread that serves a request with
pthread_create(&thread, NULL, &php_thread, ...)— NULL attributes, so muslpicks the stack size. musl takes that from the main executable's
PT_GNU_STACKheader, and
/usr/bin/frankenphpships with it at zero:so every PHP thread gets musl's 128KB fallback, where php-fpm's main thread gets
8MB. PHP 8.3+ auto-detects
zend.max_allowed_stack_sizefrom the real stack, andthe arithmetic lands exactly on the reported number: 131072 - 47136 = 83936.
Nothing app-specific about it — it is the first page load of a stock Symfony app.
Fix
Rewrite that header field to 8MB at build time. This is the same thing upstream's
-Wl,-z,stack-size=...build flag does; we install frankenphp prebuilt frompkg.henderkes.com, so a small helper (
elf-stack-size) writes the fieldafterwards instead. 8MB is both what php-fpm gets and musl's ceiling — asking for
32MB still measures 8341472 usable, so it clamps.
Why not
zend.max_allowed_stack_size = -1It clears the symptom by removing the guard, not by giving PHP a stack. Confirmed
on a built image with
-1in place: a runaway recursion no longer raises a PHPError, it takes the worker thread down and the request dies withcurl: (52) Empty reply from server. With the stack sized instead, the guardstays armed and just reports the larger limit.
Verified in a built image (arm64, PHP 8.5)
Error, limit 83936 bytesError, limit 8341472 bytesmatthewbaggett/php:8.5(php-fpm)Deeper than that, both images fail the same clean way php-fpm does
(
Parse error: memory exhaustedfrom the parser), so no crash band is opened up.Test coverage
etc/validate.d/frankenphp.shasserts the header at build time on every PHPversion — building with the patch step removed now fails the build.
frankenphp-85-stack-healthchecksservice asserts both directions atruntime: that a deeply nested template compiles and that infinite recursion
is still caught. It is wired into the
test-frankenphpgroup (CI cannot runthese images; run
./test test-frankenphpby hand)../testand./test test-frankenphpboth pass locally.Closes #25