Skip to content

Segmentation fault in PHP 8.1 #8461

Closed
Closed

Description

@oleg-st

Description

The problem is quite difficult to reproduce.
Need to change php files when running specific application in php-fpm.

Steps to reproduce:

  1. Turn on JIT, Opcache
opcache.jit_buffer_size=100M
opcache.jit=1255
  1. Extract
    bugphp.zip
  2. Use ab to execute run.php from bugphp.zip:
ab -n 5000 -c 20 http://localhost/run.php

Application touches UniqueList.php to make it modified for the OPcache.

Segmentation faults:

[29-Apr-2022 15:07:30] NOTICE: ready to handle connections
[29-Apr-2022 15:07:33] WARNING: [pool www] child 338824 exited on signal 11 (SIGSEGV - core dumped) after 2.980459 seconds from start
[29-Apr-2022 15:07:33] NOTICE: [pool www] child 338841 started
[29-Apr-2022 15:07:33] WARNING: [pool www] child 338827 exited on signal 11 (SIGSEGV - core dumped) after 2.980157 seconds from start
[29-Apr-2022 15:07:33] NOTICE: [pool www] child 338842 started
[29-Apr-2022 15:07:33] WARNING: [pool www] child 338826 exited on signal 11 (SIGSEGV - core dumped) after 2.999109 seconds from start

Backtrace:

#0  0x00000000008a47d1 in ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_CONST_HANDLER ()
    at /home/Oleg.Stepanischev/php-src/Zend/zend_vm_execute.h:33346
#1  0x00000000008cdcd3 in execute_ex (ex=0x7fb8c7c14020) at /home/Oleg.Stepanischev/php-src/Zend/zend_vm_execute.h:58689
#2  0x00000000008cf41b in zend_execute (op_array=0x7fb8c7c67000, return_value=0x0)
    at /home/Oleg.Stepanischev/php-src/Zend/zend_vm_execute.h:60123
#3  0x00000000008231b3 in zend_execute_scripts (type=8, retval=0x0, file_count=3)
    at /home/Oleg.Stepanischev/php-src/Zend/zend.c:1792
#4  0x000000000078bbd4 in php_execute_script (primary_file=0x7ffdc50da360) at /home/Oleg.Stepanischev/php-src/main/main.c:2538
#5  0x00000000009901d9 in main (argc=2, argv=0x7ffdc50da578) at /home/Oleg.Stepanischev/php-src/sapi/fpm/fpm/fpm_main.c:1914

Bisect found the commit that contains the problem: 4b79dba
Disabling inheritance cache solves the problem.
The UniqueList class has a child class UniqueListLast that uses some of the parent class's constants. And the modification of the parent class somehow leads to the problem.

Possible related to #7817

PHP Version

PHP 8.1

Operating System

AlmaLinux release 8.5 (Arctic Sphynx)

Activity

  1. meinemitternacht commented on Apr 29, 2022

    @meinemitternacht

    I'm pretty sure this is the source of the problems in #7817. In our application (embedded hardware), there are several PHP files that are generated by other C programs which are overwritten often.

  2. bolknote commented on Apr 29, 2022

    @bolknote
    Contributor

    Wow! Great job, Oleg!

  3. self-assigned this
    on May 4, 2022
  4. oleg-st commented on May 4, 2022

    @oleg-st
    ContributorAuthor

    After some research, I found that the problem occurs here https://github.com/php/php-src/blob/PHP-8.1/ext/opcache/jit/zend_jit_x86.dasc#L10044
    func->op_array.run_time_cache__ptr changes when the file with the called function is reloaded. I don't know if it was intended or not. This causes the run_time_cache to be loaded incorrectly.

  5. arnaud-lb commented on May 4, 2022

    @arnaud-lb
    Member

    I confirm this. The run_time_cache__ptr of the sub class constructor changes when the parent class is recompiled.

    The crash happens because the old run_time_cache offset is still used by the generated code.

    Change of the run_time_cache__ptr happens during zend_do_link_class, when the inheritance cache is persisted.

    Reverting the changes made by JIT on the op array would fix the issue. I think that we are not supposed to reuse the JIT code here.

  6. oleg-st commented on May 5, 2022

    @oleg-st
    ContributorAuthor

    A simple fix is to remove 2 branches with specific cases and leave one generic:
    https://github.com/php/php-src/blob/PHP-8.1/ext/opcache/jit/zend_jit_x86.dasc#L10069

    It's also strange that the second branch uses run_time_cache__ptr as an offset, but the first branch has already fully covered this case.

    To remove the JIT code in this case, I think we need to remove the JIT code of all callers when the callee code changes.

  7. oleg-st commented on May 12, 2022

    @oleg-st
    ContributorAuthor

    Tested with #8535, everything works fine for me

  8. rs-orlov commented on Sep 8, 2023

    @rs-orlov

    @oleg-st what do you mean by "Disabling inheritance cache ...", did you just dropped commit and built php without it? Or is there a reasonably small patch which makes inheritance cache effectively disabled?

    We have another issue with inheritance cache. It blocks us from upgrading php version. Considering amount of time issue hangs without any movement, disabling inheritance cache (even by patching php) seems to be not so bad alternative.

  9. oleg-st commented on Sep 10, 2023

    @oleg-st
    ContributorAuthor

    @rs-orlov
    This can be done by commenting out these 2 lines:

    zend_inheritance_cache_get = zend_accel_inheritance_cache_get;
    zend_inheritance_cache_add = zend_accel_inheritance_cache_add;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions