Skip to content

PHP 8.3.7 with JIT encounters infinite loop on specific paths #14475

Closed
@Appla

Description

@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
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
#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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions