php / php/php-src

Segfault in PHP-FPM with tracing JIT (opcache.jit=1205) due to stale base pointer in rbp (Regression in 8.5.5)

Đang mở
#22,084 7 bình luận 9 reaction 1 người được giao Xem trên GitHub

@arnaud-lb đang làm issue này rồi.

Từ ngày 26/8/2026.

Bug Category: JIT SAPI: fpm
Ngôn ngữ chính
C
Star
40.4k
Fork
8.2k
Merge trung bình
2 ngày 15 giờ
Pull request đã merge (30 ngày)
103

Mô tả

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-fpm Docker 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_size reduced, or specific opcache.jit_* tuning

Switching to opcache.jit=1235 is a viable workaround for now.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.