Skip to content

Segfault in zend_accel_class_hash_copy #9164

Closed
@turchanov

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

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