php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78918 Segfault with preloading Laravel
Submitted: 2019-12-06 12:31 UTC Modified: 2019-12-28 19:15 UTC
Votes:15
Avg. Score:4.5 ± 0.8
Reproduced:11 of 12 (91.7%)
Same Version:10 (90.9%)
Same OS:5 (45.5%)
From: brent at spatie dot be Assigned: nikic (profile)
Status: Closed Package: opcache
PHP Version: 7.4.0 OS: macOS 10.14
Private report: No CVE-ID: None
 [2019-12-06 12:31 UTC] brent at spatie dot be
Description:
------------
I'm trying to preload a Laravel project. php-fpm is able to boot with the preloaded files, and `opcache_get_status` shows around 100 files are preloaded.

However, as soon as the Laravel kernels boots, php-fpm segfaults:

[06-Dec-2019 13:21:24] WARNING: [pool www] child 49201 exited on signal 11 (SIGSEGV) after 119.491091 seconds from start

I've tried using dbg to get some more information, but this is all:

0x00007fff7c4eb78e in ?? () from /usr/lib/system/libsystem_kernel.dylib



Test script:
---------------
The project: https://github.com/brendt/aggregate.stitcher.io

The preload file: https://github.com/brendt/aggregate.stitcher.io/blob/master/preload.php

The segfault happens as soon as `$kernel->handle` is called: https://github.com/brendt/aggregate.stitcher.io/blob/master/public/index.php#L47


Patches

Pull Requests

Pull requests:

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-12-09 09:00 UTC] nikic@php.net
-Status: Open +Status: Verified
 [2019-12-09 09:00 UTC] nikic@php.net
At the least there is an assertion failure during initial preloading:

php: /home/nikic/php-7.4/Zend/zend_hash.c:1019: _zend_hash_index_add_or_update_i: Assertion `(flag & (1<<3)) == 0' failed.
Aborted

#4  0x0000555555d9aaad in _zend_hash_index_add_or_update_i (ht=0x7fffeab4cd50 <accel_globals+368>, 
    h=17592143058440, pData=0x7fffffffcf30, flag=10) at /home/nikic/php-7.4/Zend/zend_hash.c:1019
#5  0x0000555555d9ad77 in zend_hash_index_add_new (ht=0x7fffeab4cd50 <accel_globals+368>, 
    h=17592143058440, pData=0x7fffffffcf30) at /home/nikic/php-7.4/Zend/zend_hash.c:1068
#6  0x00007fffea8acfff in zend_hash_index_add_new_ptr (ht=0x7fffeab4cd50 <accel_globals+368>, 
    h=17592143058440, pData=0x7fffe360fbe8) at /home/nikic/php-7.4/Zend/zend_hash.h:746
#7  0x00007fffea8ade22 in _zend_shared_memdup (source=0x7fffeb80b040, size=456, arena=0 '\000', 
    get_xlat=0 '\000', set_xlat=1 '\001', free_source=0 '\000')
    at /home/nikic/php-7.4/ext/opcache/zend_shared_alloc.c:387
#8  0x00007fffea8adf67 in zend_shared_memdup_put (source=0x7fffeb80b040, size=456)
    at /home/nikic/php-7.4/ext/opcache/zend_shared_alloc.c:417
#9  0x00007fffea8958d6 in zend_persist_class_entry (zv=0x7fffe3132de0)
    at /home/nikic/php-7.4/ext/opcache/zend_persist.c:708
#10 0x00007fffea898de1 in zend_accel_persist_class_table (class_table=0x7fffe312f4a0)
    at /home/nikic/php-7.4/ext/opcache/zend_persist.c:1032
#11 0x00007fffea8990f9 in zend_accel_script_persist (script=0x7fffe312f380, key=0x0, key_length=0, 
    for_shm=1) at /home/nikic/php-7.4/ext/opcache/zend_persist.c:1074
#12 0x00007fffea88b3cf in preload_script_in_shared_memory (new_persistent_script=0x7fffe2487a00)
    at /home/nikic/php-7.4/ext/opcache/ZendAccelerator.c:4092
#13 0x00007fffea88c986 in accel_preload (config=0x555556bdebe8 "preload.php")
    at /home/nikic/php-7.4/ext/opcache/ZendAccelerator.c:4413
#14 0x00007fffea88d334 in accel_finish_startup ()
    at /home/nikic/php-7.4/ext/opcache/ZendAccelerator.c:4644
#15 0x00007fffea887c6b in accel_post_startup ()
    at /home/nikic/php-7.4/ext/opcache/ZendAccelerator.c:3024
#16 0x0000555555d830ec in zend_post_startup () at /home/nikic/php-7.4/Zend/zend.c:1000
 [2019-12-09 09:08 UTC] nikic@php.net
Okay, that one's easy to repro:

<?php
class A {}
class_alias(A::class, 'B');

This results in the class being in the class table twice, and we don't take that into account.
 [2019-12-09 13:43 UTC] themohamedsaid at gmail dot com
After disabling all aliases and making sure class_alias is not used, I still get a segfault.

WARNING: [pool www] child 18450 exited on signal 11 (SIGSEGV - core dumped) after 1.191760 seconds from start
 [2019-12-09 14:03 UTC] nikic@php.net
We've found some fundamental design problems in the preloading functionality today ...

The tl;dr is that you need to use opcache_compile_file() based preloading for now. Preloading based on require calls has a whole series of issues that may result in crashes.
 [2019-12-09 17:05 UTC] themohamedsaid at gmail dot com
Unfortunately I keep getting a segfault even when switching to opcache_compile_file() and restarting php-fpm.

Wish I had more input to provide
 [2019-12-10 10:40 UTC] fosron at gmail dot com
I've tested preloading Laravel too, and i'm getting "zend_mm_heap corrupted" with this script (https://github.com/brendt/laravel-preload/blob/master/preload.php) on a Docker container (both require and opcache_compile_file options don't work).
 [2019-12-10 12:59 UTC] nikic@php.net
-Status: Verified +Status: Feedback
 [2019-12-10 12:59 UTC] nikic@php.net
Support for class aliases has been added, and issues relating to classes with unresolved initializers fixed.

You will not get a fatal error if you try to preload a class with unresolved initializers under the "require" model (under the opcache_compile_file() model a graceful fallback is possible). However, opcache will try harder to make sure everything can be resolved.

I was not able to test preloading Laravel due to https://github.com/briannesbitt/Carbon/blob/298d9f0e8e369301b0ca647f3ce9c92b53ad3a82/src/Carbon/Traits/Date.php#L541-L556. This references constants that are not defined in the trait and are only available in the class using the trait. This will need to either be fixed, or the trait and it's dependencies skipped.
 [2019-12-10 13:19 UTC] cmb@php.net
> You will not get a fatal error […]

That is supposed to be "You will now get a fatal error […]".
 [2019-12-11 00:34 UTC] hopeseekr at gmail dot com
I would have guessed someone would have run Laravel's phpunit test suite while and after developing something as inner-touching as preloading.

Guess not! Probably didn't run Symonfy's tests either.
 [2019-12-11 08:02 UTC] nikic@php.net
Additional failure case in class alias support:

interface I {}
class B implements I {}
class_alias('B', 'C');

update_parent_ce does not handle duplicate classes correctly.
 [2019-12-11 09:34 UTC] nikic@php.net
The additional class_alias issue is fixed by https://github.com/php/php-src/commit/3280209c0312df000d558e029aa4e8c63912967a.
 [2019-12-16 09:05 UTC] brent at spatie dot be
Hi Nikita

I just used 7.4.1-RC1 to try out these changes. I didn't look too hard into the Carbon issue for now, and simply removed the constant references in the vendor folder, so that I'd be able to do my tests.

Unfortunately there's still a segfault, the same one:

0x00007fff7c4eb78e in ?? () from /usr/lib/system/libsystem_kernel.dylib

php-fpm is able to start and preload files, it's only after sending a request that the and when the Laravel kernel is triggered that the segfault happens. 

When opcache.preload is disabled in php.ini, things just work fine. Let me know if there's anything else I can test.
 [2019-12-16 09:07 UTC] nikic@php.net
@brent: Can you please check whether it works with the built-in web server?
 [2019-12-16 09:12 UTC] nikic@php.net
I should probably clarify that 7.4.1 will not contain all the preloading fixes. Some of them will only make 7.4.2 (current 7.4 branch).
 [2019-12-16 12:02 UTC] brent at spatie dot be
Hi Nikita

Running it with the built-in server also gives a segfault:

[Preloader] Preloaded 192 classes
[Mon Dec 16 13:00:51 2019] PHP 7.4.1RC1 Development Server (http://localhost:8181) started
[Mon Dec 16 13:00:53 2019] [::1]:54280 Accepted
[Mon Dec 16 13:00:53 2019] [::1]:54281 Accepted
[1]    21300 segmentation fault  /Users/brent/dev/php/build/php-741-RC1/bin/php -S localhost:8181 -t public

I'll give the 7.4 branch a try later today or tomorrow though.
 [2019-12-17 15:01 UTC] brent at spatie dot be
Hi Nikita

I've used PHP 7.4.1-dev now (commit https://github.com/php/php-src/commit/5ddcacac)

I'm still getting a segfault:

[1]    86293 segmentation fault  <php path>/bin/php -S localhost:8181 -t public

Using gdb I've got this (still no idea if this is useful at all for you)

0x00007fff7c4ec61a in ?? () from /usr/lib/system/libsystem_kernel.dylib

When I don't preload any classes, yet still provide a preload script, there's another segfault:

[1]    90260 segmentation fault  <php path>/bin/php -S localhost:8181 -t public

And finally, when opcache.preload and opcache.preload_user options are omitted in php.ini, the server works fine.
 [2019-12-17 15:36 UTC] bugreports at gmail dot com
> [2019-12-17 15:01 UTC] brent at spatie dot be
> I've used PHP 7.4.1-dev now (commit https://github.com/php/php-src/commit/5ddcacac)

why?
7.4.1.dev is stone old when it comes to recent fixes
https://git.php.net/?p=php-src.git;a=shortlog;h=refs/heads/PHP-7.4
 [2019-12-18 11:12 UTC] nikic@php.net
Unfortunately I'm not able to reproduce the segfault on Ubuntu. To make sure we're on the same page, here's what I do:

 * Clone the git@github.com:brendt/aggregate.stitcher.io.git repo
 * Run ~/php-7.4/sapi/cli/php composer.phar install
 * Patch vendor/nesbot/carbon/src/Carbon/Traits/Date.php to comment out the problematic $days static property.
 * Run the following command:
   ~/php-7.4/sapi/cli/php -c ~/php-7.4/php.ini -d opcache.preload=preload.php -S localhost:8000 -t public
 * Open localhost:8000 in the browser

Does this match what you're doing?

> Using gdb I've got this (still no idea if this is useful at all for you)
> 
> 0x00007fff7c4ec61a in ?? () from /usr/lib/system/libsystem_kernel.dylib

Is this the full backtrace? Do you get anything more when typing "backtrace" into gdb?
 [2019-12-20 13:12 UTC] brent at spatie dot be
Hi Nikita

It's working now with the latest 7.4 build (7.4.2-dev). That's great! I'm getting some "already declared class" warnings still, but I guess that has to do with my preload script, stuff like ": Cannot declare interface Nette\DI\Config\IAdapter, because the name is already in use in
/Users/brent/dev/spatie/aggregate.stitcher.io/vendor/nette/di/src/compatibility.php"

I guess this one can be closed though, thank you for looking into this :)
 [2019-12-20 13:16 UTC] brent at spatie dot be
Update: I've now also tested this with php-fpm, it also works.
 [2019-12-28 19:15 UTC] nikic@php.net
-Status: Feedback +Status: Closed -Assigned To: +Assigned To: nikic
 [2019-12-28 19:15 UTC] nikic@php.net
Thanks brent for checking. I'll close this issue -- let's open new bugs for any followup problems.
 [2021-02-18 10:10 UTC] mggaccou dot t at gmail dot com25
The following pull request has been associated:

Patch Name: Prepare for longer commit hashes
On GitHub:  https://github.com/php/web-windows/pull/24
Patch:      https://github.com/php/web-windows/pull/24.patch
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed Dec 04 17:01:29 2024 UTC