[php-src] PR #24273: Fix JIT stub veneers being reused after an OPcache restart on AArch64
| From: | pavimus | Date: | Mon, 12 Oct 2026 13:36:51 +0000 |
| Subject: | [php-src] PR #24273: Fix JIT stub veneers being reused after an OPcache restart on AArch64 | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-39357@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/24273
Author: pavimus
Prepared with an AI assistant (Claude), which also ran the reproduction and the tests on my machine;
I reviewed the result. The text below is AI-generated (quoted, as asked in CONTRIBUTING.md).
> While testing OPcache restarts with tracing JIT on AArch64 we found crashes caused by a JIT
> issue that is independent of threading.
>
> On AArch64 a branch from JIT code to a stub can be out of range (conditional branches reach
> ±1 MB), and IR emits a veneer next to the new code.
>
zend_jit_set_veneer() /
> zend_jit_commit_veneers() then replace the address of the stub
> in zend_jit_stub_handlers[]
> by the address of that veneer, so that later code reuses it.
>
> These veneers live after the JIT restart point (dasm_ptr[1]).
> zend_jit_restart() rewinds the
> buffer to that point but leaves zend_jit_stub_handlers[]
> pointing to the old veneers. Code
> compiled after the restart branches to those addresses, which are overwritten by new traces as
> the
> buffer fills up again, and jumps into the middle of unrelated code when the stub is taken
> (exception handling, leaving a function, ...).
>
> Observed with opcache.jit=tracing, more than 1 MB of JIT code
> and repeated OOM restarts under
> FrankenPHP (ZTS): crash in JIT code in 8 of 8 runs. At the crash, gdb shows e.g.
> zend_jit_stub_handlers[JIT$$leave_function_handler] ==
> $pc, and that address holds an ldr
> of a trace, not the b of a veneer. In a single-process NTS
> server the same stale entries are
> present at zend_jit_restart()
> (JIT$$exception_handler,
> JIT$$leave_function_handler,
> JIT$$icall_throw,
> JIT$$leave_throw pointing past the restart point); we did not manage
> to turn
> that into a deterministic crash in NTS, so there is no test yet.
>
> The fix keeps the original stub addresses in a third block after the pending veneers (allocated
> in
> the same place as the existing two) and restores them in
> zend_jit_restart(). x86 and Windows
> are not affected (no veneers).
>
> With this change (and the GH-8739 fix, which is needed to have restarts at all under ZTS): 0
> crashes
> in 40 runs of the FrankenPHP scenario, and 9 of 10 runs without a crash on Apache event (the
> remaining
> crash has a different signature and is not understood yet). make
> test for ext/opcache and
> Zend/tests passes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)