Soit une installation nginx + php-fpm + mysql tout à fait standard avec un CMS (WordPress mais ce qui suit est applicable à tout script PHP) fraîchement installé (aucun plugin, aucun thème mais peut-être du contenu) mais pas par nous. Pas de modules PHP "chelous" installés (ls -lh /etc/php5/mods-available
) comme memcached. Quand on accède au site web, nginx nous répond « 502 Bad Gateway Error ».
Dans le log de nginx, on a :
recv() failed (104: Connection reset by peer) while reading response header from upstream
Dans le log php-fpm (/var/log/php5-fpm.log par défaut sous Debian), on a :
[...] child [...] exited on signal 11 (SIGSEGV) after [...]
À chaque fois que l'on accède au WordPress, vlam, segfault. Si l'on n'y accède pas : il ne se passe rien. Ce n'est pas le paramètre « pm.max_children » qui est atteint.
On a assez de RAM (1,5G libre :D ). La valeur de memory_limit
, 128M, est amplement suffisante pour un WordPress (même mon WP avec des posts longs d'une centaine de pages A4 se contente de 64M :D).
Sur un moteur de recherche, on trouve que cela peut être un problème d'accès en écriture au dossier dans lequel sont créés les fichiers relatifs aux sessions, session.save_path
(/var/lib/php5/sessions par défaut sous Debian). Il n'en est rien pour moi.
De même, on trouve que cela peut être relatif à opcache dans des cas très particuliers. Exemple : https://serverfault.com/questions/629231/how-can-a-bog-standard-wordpress-install-break-php . Même en désactivant opcache (mv /etc/php5/mods-available/opcache.conf /root/ ; systemctl restart php5-fpm
), ça ne fonctionne pas.
On tente d'exécuter l'index du WP avec php-cli genre sudo php /chemin/vers/WP/index.php
. sudo pour éviter les problèmes de permissions pour les « require() ». « Erreur de segmentation ». Même erreur, donc.
Bon, on se résout à sortir strace : sudo strace php /chemin/vers/WP/index.php
. On voit PHP communiquer avec MySQL pour récupérer les articles, les commentaires, etc. puis une 20aine d'appels systèmes « brk() » puis SIGSEGV. brk() permet d'allouer de la RAM. Pourtant, on a déjà vu que l'on a bien assez de RAM. Ha, pour que strace ne tronque pas les paramètres des appels systèmes : strace -s 9999
.
On se résout à demander la création d'un core dump et à l'analyser. Voir cet excellent tuto : https://ma.ttias.be/generate-php-core-dumps-segfaults-php-fpm/ . Sous Debian, il faut aussi installer les symboles de debug qui sont packagés séparément (car ça consomme de l'espace disque sans pour autant être utile au plus grand nombre de personnes) : apt-get install php5-dbg
.
On constate que notre bt a plus de 30 000 appels de fonctions et que c'est toujours les 3 mêmes :
#30829 0x002219c0 in execute_ex (execute_data=execute_data@entry=0xb87988) at /build/php5-3mKzyG/php5-5.6.27+dfsg/Zend/zend_vm_execute.h:363
#30830 0x001ee2f6 in dtrace_execute_ex (execute_data=0xb87988) at /build/php5-3mKzyG/php5-5.6.27+dfsg/Zend/zend_dtrace.c:73
#30831 0x0026d460 in zend_do_fcall_common_helper_SPEC (execute_data=) at /build/php5-3mKzyG/php5-5.6.27+dfsg/Zend/zend_vm_execute.h:592
Conclusion : il y a une boucle infinie dans un des fichiers .php et l'erreur de segmentation vient du fait que PHP explose sa pile.
Pour savoir dans quel fichier et quelle ligne, soit on installe xdebug (mes notes sont ici http://shaarli.guiguishow.info/?7b7cDA ) soit on tente sa chance en cherchant les derniers fichiers modifiés genre find -type f -mtime -2
. Sur un CMS où la craderie peut avoir été faite n'importe où, la deuxième méthode est intenable sauf sur un coup de chance (et quand xdebug vous rebute, vous croyez subitement à la notion de chance :D).
Au final, on se souvient qu'il n'y a pas de limite de récursion par défaut en PHP. Cette limite existe uniquement si l'on a installé xdebug.