Skip to content

Segfault in zend_accel_class_hash_copy #9164

Closed

Description

@turchanov

Description

We use php-fpm with opcache with filecache, no JIT. On deployment of a newer version of php application codebase (that is opcache filecache is empty at the moment) we experience a spike of segfaults in php-fpm workers. This bug seems to be relevant to https://bugs.php.net/bug.php?id=81607 as we see that ce->name->gc->refcount / 8 is beyond the limits of CG(map_ptr_last)

#0  0x00007fd7b8a9e67a in zend_accel_class_hash_copy (target=0x26aa520, source=0x47dc6cf0)
    at /usr/src/debug/php-8.1.8-debug/ext/opcache/zend_accelerator_util_funcs.c:210
#1  0x00007fd7b8a9e870 in zend_accel_load_script (persistent_script=0x47dc6bc0, from_shared_memory=1)
    at /usr/src/debug/php-8.1.8-debug/ext/opcache/zend_accelerator_util_funcs.c:230
#2  0x00007fd7b8a6a2d8 in persistent_compile_file (file_handle=0x7ffd3264a1b0, type=2)
    at /usr/src/debug/php-8.1.8-debug/ext/opcache/ZendAccelerator.c:2240
#3  0x000000000099e6bf in compile_filename (type=2, filename=0x426aac80) at /usr/src/debug/php-8.1.8-debug/Zend/zend_language_scanner.c:707
#4  0x0000000000a7886c in zend_include_or_eval (inc_filename_zv=0x7fd7b4015ac0, type=2)
    at /usr/src/debug/php-8.1.8-debug/Zend/zend_execute.c:4617
(gdb) fr 0
   |204                     } else {
   |205                             zend_class_entry *ce = Z_PTR(p->val);
   |206                             t = _zend_hash_append_ptr_ex(target, p->key, Z_PTR(p->val), 1);
   |207                             if ((ce->ce_flags & ZEND_ACC_LINKED)
   |208                              && ZSTR_HAS_CE_CACHE(ce->name)
   |209                              && ZSTR_VAL(p->key)[0]) {
  >|210                                     ZSTR_SET_CE_CACHE_EX(ce->name, ce, 0);  <----
   |211                             }
   |212                     }

(gdb) print compiler_globals->map_ptr_base
$1 = (void *) 0x7fd7a7a6000f

(gdb) print compiler_globals->map_ptr_last
$2 = 57332

(gdb) print ce->name->gc->refcount
$3 = 472001

(gdb) print ce->name->gc->refcount / 8
$4 = 59000

We implemented a work-around by reverting ZSTR_SET_CE_CACHE_EX(ce->name, ce, 0) to ZSTR_SET_CE_CACHE(ce->name, ce) in zend_accel_class_hash_copy (and in zend_accel_inheritance_cache_get and zend_persist_class_entry just in case) as it appears that invalid cache pointers do exists at this point. With this fix segfauls do not happen anymore.

opcache settings:

zend_extension=opcache.so
opcache.enable = 1
opcache.max_accelerated_files = 50000
opcache.interned_strings_buffer = 50
opcache.memory_consumption = 320
opcache.revalidate_freq = 15
opcache.enable_file_override = 1
opcache.file_cache = "..."

PHP Version

PHP 8.1.8

Operating System

CentOS 7.7

Activity

  1. turchanov commented on Jul 27, 2022

    @turchanov
    ContributorAuthor

    This bug also happens in 8.1.6. This is the first version of 8.1.x series on which we tried to run our production load.

  2. added 2 commits that reference this issue on Aug 1, 2022
    a697083
    bccda7e
  3. arnaud-lb commented on Aug 1, 2022

    @arnaud-lb
    Member

    Fixed #9188. Thank you for the high quality bug report!

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

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