Segfault in PHP-FPM with tracing JIT (opcache.jit=1205) due to stale base pointer in rbp (Regression in 8.5.5)
@arnaud-lb is already working on this.
Since Aug 26, 2026.
- Dominant language
- C
- Stars
- 40.4k
- Forks
- 8.1k
- Avg merge
- 2d 13h
- Merged PRs (30d)
- 96
Description
Description
After upgrading from PHP 8.5.4 to 8.5.5, php-fpm workers started
segfaulting deterministically under normal web traffic. Issue persists
on 8.5.6. Only tracing JIT (opcache.jit=1205) is affected; function
JIT (1235) and disabled JIT both work fine.
Environment
- PHP 8.5.5 and 8.5.6 (official
php:8.5.6-fpmDocker image, Debian Trixie base) - x86_64
- Application: Nette Framework + Dibi 5.1.1 + ext/mysqli, MariaDB 11.8
JIT configuration matrix
| opcache.jit | Result |
|---|---|
| 1205 (tracing) | Workers segfault within seconds of receiving traffic |
| 1235 (function) | Stable |
| off | Stable |
PHP 8.5.4 with opcache.jit=1205 was stable. Regression introduced in
8.5.5, not resolved in 8.5.6.
opcache config
opcache.enable=1
opcache.memory_consumption=256
opcache.jit=1205
opcache.jit_buffer_size=128M
Crash signature (host dmesg)
Repeated segfaults at a small, stable set of offsets in the php-fpm binary (binary base changes due to ASLR; offsets are consistent):
php-fpm[294862]: segfault at 7e3e1bc12bc0 ip ...4c9466 ... error 4 in php-fpm[4c9466,...+801000]
php-fpm[515992]: segfault at 702b7efcdf8c ip ...4bc8a6 ... error 4 in php-fpm[4bc8a6,...+801000]
php-fpm[521652]: segfault at 7b4425b40ca0 ip ...4bc17b ... error 4 in php-fpm[4bc17b,...+801000]
php-fpm[529400]: segfault at 72f91dc4c1c0 ip ...4c9421 ... error 4 in php-fpm[4c9421,...+801000]
error 4 = user-mode read fault on unmapped page. Fault addresses are
high (7e…, 7b…, 72…), consistent with reads through a stale pointer.
Disassembly at crash offsets
Official Docker image is stripped, so all faulting offsets fall under
the preceding exported symbol opcache_preloading@@Base. The actual
crashing code is unexported, almost certainly JIT-generated VM handler
inlines.
Faulting instruction at 4c9466 (inside a tight loop):
4c9460: mov (%rax),%esi ; load 32-bit index from source
4c9462: add $0x4,%rax ; advance source pointer
4c9466: mov 0x0(%rbp,%rsi,4),%esi ; <-- FAULT: rbp[rsi*4]
Faulting instruction at 4c9421:
4c940d: movslq -0x2c(%rdx),%rdi
4c9411: cmp %r8d,0x74(%r15) ; bounds check vs. value at r15+0x74
4c9415: jb 4c94b7 <...> ; branch if below
4c941b: mov 0x1c(%rdx),%eax ; load constant index (op_array slot?)
4c941e: mov 0x10(%rdx),%esi
4c9421: mov 0x0(%rbp,%rax,4),%eax ; <-- FAULT: rbp[rax*4]
Both faulting instructions are mov [rbp + reg*4], reg32 — 32-bit
indexed loads consistent with PHP literal/constant pool lookup
(op_array->literals is a zval[] accessed by 32-bit indices from
zend_op operands). The rbp register holds what appears to be a
stale base pointer pointing into freed memory.
Hypothesis
JIT-compiled tracing code appears to hold a base pointer (possibly
op_array->literals) across a point where the underlying memory is
freed or moved, then dereferences it via a stable 32-bit index from
the opcode stream. Maintainers will know better — this is only a
guess based on the instruction pattern.
Possibly related: GH-21395 (UAF in JIT, fixed in 8.5.5). The fix may be incomplete, or it may have introduced an adjacent regression. Tracing-only failure (function JIT works) strongly suggests a tracing-specific bug, e.g. in trace recording / side-exit assumptions about value lifetimes.
Reproduction
Plain web traffic against the application is enough; workers crash within seconds. Happy to provide:
- The specific application code paths (Nette controller, Dibi queries)
- Larger dmesg samples
- strace / ltrace output
- A core dump (can be arranged if you can guide on getting useful symbols from the official php-fpm image)
- Test with
opcache.jit_buffer_sizereduced, or specificopcache.jit_*tuning
Switching to opcache.jit=1235 is a viable workaround for now.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.