Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:116684 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 82196 invoked from network); 20 Dec 2021 17:37:47 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 20 Dec 2021 17:37:47 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id D336B1804E3 for ; Mon, 20 Dec 2021 10:41:17 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=BAYES_00,SPF_HELO_PASS, SPF_NEUTRAL autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS30827 82.113.144.0/20 X-Spam-Virus: No X-Envelope-From: Received: from xdebug.org (xdebug.org [82.113.146.227]) by php-smtp4.php.net (Postfix) with ESMTP for ; Mon, 20 Dec 2021 10:41:17 -0800 (PST) Received: from localhost (localhost [IPv6:::1]) by xdebug.org (Postfix) with ESMTPS id ABF6B10C035; Mon, 20 Dec 2021 18:41:15 +0000 (GMT) Date: Mon, 20 Dec 2021 18:41:15 +0000 (GMT) X-X-Sender: derick@singlemalt.home.derickrethans.nl To: Jakub Zelenka cc: PHP Developers Mailing List Message-ID: User-Agent: Alpine 2.23 (DEB 453 2020-06-18) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="8323329-501048510-1640025675=:539437" Subject: PHP-FPM process management woes From: derick@php.net (Derick Rethans) --8323329-501048510-1640025675=:539437 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Hi! In the last few days I have been investigating Xdebug bug #2051:=20 "Segfault on fatal error when setting xdebug.mode via php-fpm pool=20 config" (https://bugs.xdebug.org/view.php?id=3D2051). I have now tracked this down to an unexpectedness in how PHP-FPM handles=20 extension/module initialisation. Literature since at least 2006 (Sara's Extending and Embedding PHP=20 book), as well as numerous presentations that I have seen and given, and=20 including the online PHP Internals Book=20 (https://www.phpinternalsbook.com/php7/extensions_design/php_lifecycle.html= ),=20 always expected that the MINIT (and MSHUTDOWN) functions are called once=20 per worker process. However, PHP-FPM does not do that. It only calls=20 extension's MINITs once in the main control process, but it *does* call=20 an MSHUTDOWN for each worker process. In the past, this has already caused an issue where I couldn't create a=20 monitoring thread in MINIT, and then wait for it to end in MSHUTDOWN, as=20 MSHUTDOWN would wait on the same thread in each worker process, although=20 only one was created in MINIT. The way how PHP-FPM handles this breaks the generally assumed "one=20 MINIT, one MSHUTDOWN call" per process approach. In particular, in the case of Xdebug bug #2051 it creates a problem with=20 the following set-up: 1. php.ini has a `xdebug.mode=3Doff` 2. the pool configuration has a `php_admin_value[xdebug.mode] =3D debug`=20 directive=20 When PHP-FPM starts up, it calls Xdebug's MINIT, which checks the value=20 of the `xdebug.mode` INI setting. If it set to `off` it does=20 **nothing**, including setting up handles such as the zend_error_cb=20 handlers in `xdebug_base_minit`:: =09PHP_MINIT_FUNCTION(xdebug) =09{ =09=09=E2=80=A6 =09=09if (XDEBUG_MODE_IS_OFF()) { =09=09=09return SUCCESS; =09=09} =09=09=E2=80=A6 =09=09xdebug_base_minit(INIT_FUNC_ARGS_PASSTHRU); =09} MINIT sets the `xdebug_old_error_cb` and `xdebug_new_error_cb` handlers=20 to something else than `NULL`:: =09void xdebug_base_minit(INIT_FUNC_ARGS) =09{ =09=09/* Record Zend and Xdebug error callbacks, the actual setting is done= in =09=09 * base on RINIT */ =09=09xdebug_old_error_cb =3D zend_error_cb; =09=09xdebug_new_error_cb =3D xdebug_error_cb; In each RINIT, which is called once per request, it also checks the INI=20 setting, and if set, uses some of the handlers that were set-up in=20 MINIT. Please note that PHP-FPM has changed the value of `xdebug.mode`=20 in this worker process to `debug` (ie, not `off`), (simplified):: =09PHP_RINIT_FUNCTION(xdebug) =09{ =09=09=E2=80=A6 =09=09if (XDEBUG_MODE_IS_OFF()) { =09=09=09return SUCCESS; =09=09} =09=09=E2=80=A6 =09=09xdebug_base_rinit(); =09} =09void xdebug_base_rinit() =09{ =09=09xdebug_base_use_xdebug_error_cb(); =09} =09 =09void xdebug_base_use_xdebug_error_cb(void) =09{ =09=09zend_error_cb =3D xdebug_new_error_cb; =09} When now an error occurs, PHP calls `zend_error_cb`, but this is now=20 unset (`NULL`) as when MINIT was called, the `xdebug.mode` setting was=20 still set to `off`, but during RINIT it was changed by PHP-FPM to=20 `debug`. Xdebug does not expect this setting to change, especially=20 because it is marked as `PHP_INI_SYSTEM`. In my opinion this is a bug (or two) in PHP-FPM, as: - it does not follow the expected one MINIT/MSHUTDOWN cycle, that for example Apache (1 and 2) use, and which is documented in books and=20 online material (and my memory) - it disrespects `PHP_INI_SYSTEM` My suggestion for a fix would be to emulate what Apache always did: One MINIT/MSHUTDOWN in the main control process (I think it needed that=20 to be able to implement php_admin_value and php_value), and then=20 additionally also in each worker process. I did have a brief look at implementing this, but haven't managed to get=20 it to work yet =E2=80=94 mainly because I am unfamiliar with the PHP-FPM co= de at=20 the moment. cheers, Derick --=20 PHP 7.4 Release Manager Host of PHP Internals News: https://phpinternals.news Like Xdebug? Consider supporting me: https://xdebug.org/support https://derickrethans.nl | https://xdebug.org | https://dram.io twitter: @derickr and @xdebug --8323329-501048510-1640025675=:539437--