[php-src] Issue #14475: PHP 8.3.7 with JIT encounters infinite loop on specific paths

From: Date: Wed, 05 Jun 2024 06:17:41 +0000
Subject: [php-src] Issue #14475: PHP 8.3.7 with JIT encounters infinite loop on specific paths
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-247034@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/14475 Author: Appla ### Description I noticed that a PHP script was consuming a very high amount of CPU. I used strace to investigate and found that it was repeatedly executing fcntl. I used GDB to trace the process and found that it was continuously looping through a specific code path, as detailed in the following quote. One scenario is that our script is hosted under a PHP process, where the host process forks a child process to execute the specific code. * opcache.jit* settings ``` opcache.jit => tracing => tracing opcache.jit_bisect_limit => 0 => 0 opcache.jit_blacklist_root_trace => 16 => 16 opcache.jit_blacklist_side_trace => 8 => 8 opcache.jit_buffer_size => 16M => 16M opcache.jit_debug => 0 => 0 opcache.jit_hot_func => 127 => 127 opcache.jit_hot_loop => 64 => 64 opcache.jit_hot_return => 8 => 8 opcache.jit_hot_side_exit => 8 => 8 opcache.jit_max_exit_counters => 8192 => 8192 opcache.jit_max_loop_unrolls => 8 => 8 opcache.jit_max_polymorphic_calls => 2 => 2 opcache.jit_max_recursive_calls => 2 => 2 opcache.jit_max_recursive_returns => 2 => 2 opcache.jit_max_root_traces => 1024 => 1024 opcache.jit_max_side_traces => 128 => 128 opcache.jit_max_trace_length => 1024 => 1024 opcache.jit_prof_threshold => 0.005 => 0.005 ``` * GDB zbacktrace shows code in PHP land blocking on self::$traceAt = now(); * The following script just trying to show the core parts of the code which triggered the issue ```PHP namespace { function now() { return date('Y-m-d H:i:s'); } } namespace core\Context { class A { private static $traceAt; public static function resetTraceCtx() { self::$traceAt = now(); } } } namespace third { $max = 10000; $i = 0; while ($i++ < $max) { \core\Context\A::resetTraceCtx(); // poll info from queue usleep(100000); } } ``` * GDB backtrace ```backtrace #0 zend_jit_trace_exit (exit_num=0, regs=0x7ffe8841e390) at ext/opcache/jit/zend_jit_trace.c:8171 #1 0x000000001300042a in ?? () #2 0x000000000673ab60 in ?? () #3 0x0000000002d3327f in ?? () #4 0x00000000000207a9 in ?? () #5 0x0000000000680f1d in timelib_time_tz_abbr_update (tm=0x7f3d4a8157e0, tz_abbr=0x7ffe8841e510 "\200U\201J=\177") at /path/to/php-8.3.7/ext/date/lib/timelib.c:128 #6 0x0000000000000000 in ?? () ``` * loop in ASM ``` 0x000000001300042a ? add $0x100,%rsp 0x0000000013000431 ? test %eax,%eax 0x0000000013000433 ? jne 0x13000443 0x0000000013000435 ? mov 0x1a28f28,%r14 0x000000001300043d ? mov (%r14),%r15 0x0000000013000440 ? jmpq *(%r15) -> 0x0000000013000443 ? jl 0x13000330 0x0000000013000449 ? mov 0x1a28f28,%r14 0x0000000013000451 ? mov (%r14),%r15 0x0000000013000454 ? cmpb $0x0,0x1a28f56 0x000000001300045c ? jne 0x13000000 0x0000000013000462 ? mov 0x18(%r14),%rax 0x0000000013000466 ? mov 0xc0(%rax),%rax 0x000000001300046d ? mov 0xa0(%rax),%rax 0x0000000013000474 ? jmpq *(%r15,%rax,1) 0x00000000130af820 ? movl $0x3ff,0x1a28f38 0x00000000130af82b ? mov 0x40(%r14),%rdx 0x00000000130af82f ? mov 0x8(%rdx),%rax 0x00000000130af833 ? cmp $0x54306e0,%rax 0x00000000130af83a ? jne 0x130af8c0 -> 0x00000000130af840 ? mov 0x1a28f08,%r15 0x00000000130af848 ? mov 0x1a28f10,%rdx 0x00000000130af850 ? sub %r15,%rdx 0x00000000130af853 ? cmp $0x60,%rdx 0x00000000130af857 ? jb 0x13000904 0x00000000130af85d ? addq $0x60,0x1a28f08 0x00000000130af866 ? movl $0x0,0x28(%r15) 0x00000000130af86e ? mov %rax,0x18(%r15) 0x00000000130af8c0 ? mov $0x4fb4318,%rdi 0x00000000130af8c7 ? lea 0x8(%rdx),%rsi 0x00000000130af8cb ? movabs $0x7f3d4aa7e610,%rax // static zend_function* ZEND_FASTCALL zend_jit_find_ns_func_helper(zval *func_name, void **cache_slot) 0x00000000130af8d5 ? callq *%rax // return back 0x00000000130af8d7 ? cmp $0x54306e0,%rax 0x00000000130af8de ? je 0x130af840 0x00000000130af8e4 ? jmpq 0x13000900 -> 0x00000000130af8e9 ? add %al,(%rax) 0x00000000130af8eb ? add %al,(%rax) 0x00000000130af8ed ? add %al,(%rax) 0x00000000130af8ef ? add %cl,-0x39(%rcx) 0x00000000130af8f2 ? (bad) 0x00000000130af8f3 ? (bad) 0x00000000130af8f4 ? or $0x41,%al 0x0000000013000900 ? pushq $0x0 0x0000000013000902 ? jmp 0x1300097e -> 0x000000001300097e ? addq $0x0,(%rsp) 0x0000000013000983 ? jmpq 0x13000340 -> 0x0000000013000988 ? add %al,(%rax) 0x000000001300098a ? add %al,(%rax) 0x000000001300098c ? add %al,(%rax) 0x0000000013000340 ? sub $0xf8,%rsp 0x0000000013000347 ? mov %r15,0x78(%rsp) 0x000000001300034c ? mov %r11,0x58(%rsp) 0x0000000013000351 ? mov %r10,0x50(%rsp) 0x0000000013000356 ? mov %r9,0x48(%rsp) 0x000000001300035b ? mov %r8,0x40(%rsp) 0x0000000013000360 ? mov %rdi,0x38(%rsp) 0x0000000013000365 ? mov %rsi,0x30(%rsp) 0x000000001300036a ? mov %rdx,0x10(%rsp) 0x000000001300036f ? mov %rcx,0x8(%rsp) 0x0000000013000374 ? mov %rax,(%rsp) 0x0000000013000378 ? mov 0xf8(%rsp),%rdi 0x0000000013000380 ? mov %rsp,%rsi 0x0000000013000383 ? movsd %xmm15,0xf8(%rsp) 0x000000001300038d ? movsd %xmm14,0xf0(%rsp) 0x0000000013000397 ? movsd %xmm13,0xe8(%rsp) 0x00000000130003a1 ? movsd %xmm12,0xe0(%rsp) 0x00000000130003ab ? movsd %xmm11,0xd8(%rsp) 0x00000000130003ab ? movsd %xmm11,0xd8(%rsp) 0x00000000130003b5 ? movsd %xmm10,0xd0(%rsp) 0x00000000130003bf ? movsd %xmm9,0xc8(%rsp) 0x00000000130003c9 ? movsd %xmm8,0xc0(%rsp) 0x00000000130003d3 ? movsd %xmm7,0xb8(%rsp) 0x00000000130003dc ? movsd %xmm6,0xb0(%rsp) 0x00000000130003e5 ? movsd %xmm5,0xa8(%rsp) 0x00000000130003ee ? movsd %xmm4,0xa0(%rsp) 0x00000000130003f7 ? movsd %xmm3,0x98(%rsp) 0x0000000013000400 ? movsd %xmm2,0x90(%rsp) 0x0000000013000409 ? movsd %xmm1,0x88(%rsp) 0x0000000013000412 ? movsd %xmm0,0x80(%rsp) 0x000000001300041b ? mov %r15,(%r14) 0x000000001300041e ? movabs $0x7f3d4ab05090,%rax // int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs) 0x0000000013000428 ? callq *%rax 0x000000001300042a ? add $0x100,%rsp // loop again 0x0000000013000431 ? test %eax,%eax ``` ### PHP Version PHP 8.3.7 ### Operating System Rocky Linux 8

« previous php.bugs (#247034) next »