У нас на ресурсе постоянно возникает ошибка segfault — [notice] child pid 9606 exit signal Segmentation fault (11).
Ошибку удалось повторить в тестовой среде.
Для выяснения причины и решения, сначала мы сняти coredump в момент возникновения ошибки, для этого:
- Включить генерацию coredump в системе
# ulimit -с unlimited
- Убедиться, что в Apache знает куда складывать coredump
CoreDumpDirectory /tmp
- Перезапустить Apache
Дождались ошибки — получили желанный coredump.
Затем мы перенесли его в тестовую среду, где и производили дальнейшие действия.
В тестовой среде была развернута точная копия нашего приложения.
Посмотреть что происходит в coredump поможет утилита gdb:
# gdb /usr/sbin/httpd /path/to/coredump
В выводе имеем такое:
#0 0x408dfe62 in zval_mark_grey (pz=) at /usr/src/debug/php-5.3.3/Zend/zend_gc.c:372 #1 0x408e08b5 in gc_mark_roots () at /usr/src/debug/php-5.3.3/Zend/zend_gc.c:433 #2 gc_collect_cycles () at /usr/src/debug/php-5.3.3/Zend/zend_gc.c:660 #3 0x408c1fc5 in zend_deactivate () at /usr/src/debug/php-5.3.3/Zend/zend.c:900 #4 0x40868dc8 in php_request_shutdown (dummy=0x0) at /usr/src/debug/php-5.3.3/main/main.c:1634 #5 0x409508e4 in php_apache_request_dtor (r=0x520417d0) at /usr/src/debug/php-5.3.3/sapi/apache2handler/sapi_apache2.c:509 #6 php_handler (r=0x520417d0) at /usr/src/debug/php-5.3.3/sapi/apache2handler/sapi_apache2.c:681 #7 0x400266a1 in ap_run_handler (r=0x520417d0) at /usr/src/debug/httpd-2.2.15/server/config.c:158 #8 0x4002a426 in ap_invoke_handler (r=0x520417d0) at /usr/src/debug/httpd-2.2.15/server/config.c:376 #9 0x400371a8 in ap_process_request (r=0x520417d0) at /usr/src/debug/httpd-2.2.15/modules/http/http_request.c:282 #10 0x40033c98 in ap_process_http_connection (c=0x410bc878) at /usr/src/debug/httpd-2.2.15/modules/http/http_core.c:190 #11 0x4002ef11 in ap_run_process_connection (c=0x410bc878) at /usr/src/debug/httpd-2.2.15/server/connection.c:43 #12 0x4003caea in child_main (child_num_arg=) at /usr/src/debug/httpd-2.2.15/server/mpm/prefork/prefork.c:667 #13 0x4003ce7e in make_child (s=, slot=0) at /usr/src/debug/httpd-2.2.15/server/mpm/prefork/prefork.c:763 #14 0x4003de53 in perform_idle_server_maintenance (_pconf=0x4052c0a8, plog=0x4055a160, s=0x4052dfa0) at /usr/src/debug/httpd-2.2.15/server/mpm/prefork/prefork.c:898 #15 ap_mpm_run (_pconf=0x4052c0a8, plog=0x4055a160, s=0x4052dfa0) at /usr/src/debug/httpd-2.2.15/server/mpm/prefork/prefork.c:1102 #16 0x40010ad2 in main (argc=1, argv=0xbfdb2804) at /usr/src/debug/httpd-2.2.15/server/main.c:760
Для получения более подробной информации нужно собрать PHP с ключом —debug, а так же почитать как разбирать такие проблемы с php
Похожая проблема встречалась на форуме битрикса, и там же подсказки как это лечить.
Подозрение, что ошибка в garbage collector php, на github есть решение — ему мы и последовали.
Задача:
- получить исходники php
- исправить исходники php
- собрать php
У нас используется CentOS, поэтому будем пересобрали rpm пакет.
Для этого надо поставить утилиты
# yum install yum-utils rpmdevtools
Получить исходники пакета
# yumdownloader --source php
У меня yum downloader выдал:
No source RPM found for php-5.3.3-38.el6.x86_64
No source RPM found for php-5.3.3-40.el6_6.x86_64
Nothing to download
В этом случае можно получить исходники из репозитария:
# curl -O http://vault.centos.org/6.6/updates/Source/SPackages/php-5.3.3-40.el6_6.src.rpm
Устанавить src пакет:
# rpm -ivh php-5.3.3-40.el6_6.src.rpm
В результате появится дирекория rpmbuild.
Теперь нужно установить зависимости для сборки пакета.
# yum-builddep /home/имя_пользователя/rpmbuild/SPECS/php.spec
Это действие установит целую кучу необходимых dev пакетов.
Затем следует получить сам исходный код:
# rpmbuild -bp ~/rpmbuild/SPECS/php.spec
В результате будет разархивирован пакет и наложены все патчи, описанные в spec файле.
Далее сделать копию исходников, внести изменения, сделать diff:
# cp -R ~/rpmbuild/BUILD/php-5.3.3 ~/rpmbuild/BUILD/php-5.3.3-1
# vi ~/rpmbuild/BUILD/php-5.3.3-1/Zend/zend_variables.c
diff правильно надо делать из директории rpmbuild, иначе мне потом пришлось в .patch
файле указывать относительный путь к файлам.
# cd ~/rpmbuild && diff -ru ~/rpmbuild/BUILD/php-5.3.3/Zend/zend_variables.c ~/rpmbuild/BUILD/php-5.3.3-1/Zend/zend_variables.c > ~/rpmbuild/SOURCES/~/rpmbuild/SOURCES/php-5.3.3-zend-my.patch
После этого нужно изменить ~/rpmbuild/SPECS/php.spec
файл, указав в нем патч. Для этого нужно исправить секции:
- PatchN — в конце перечисления патчей указать созданный патч (например, Patch256: php-5.3.3-zend-my.patch)
- %patchN -p1 — в секцию %prep добавить созданный патч (например, %patch256 -p1 -b .zend-my)
- %changelog — ну хоть это и чисто для себя, но правило хорошего тона
Потом можно собрать rpm пакет для установки:
# rpmbuild -ba ~/rpmbuild/SPECS/php.spec
Так, как в beckend стоит apache с mod_php, пробуем подставить apache исправленный libphp5.so.
Для этого сначала надо разобрать созданный rpm пакет:
rpm2cpio php.x86_64.rpm | cpio -idmv
i: Restore archive
d: Create leading directories where needed
m: Retain previous file modification times when creating files
v: Verbose i.e. display progress
затем остановить apache
# service httpd stop
подставить ему патченый модуль
# cp -f /path/to/patchmodule/libphp5.so /usr/lib64/httpd/modules/libphp5.so
запустить apache
# service httpd start
В тестовой среде проблема ушла.
При следующем обновлении php, скорее всего, придется снова применять патченый libphp5.so. Вряд ли этот патч к этому времени попадет в основную ветку.