Skip to content

Fix unregistering ini entries of dynamically loaded extension #8435

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 6, 2022

Conversation

arnaud-lb
Copy link
Member

@arnaud-lb arnaud-lb commented Apr 24, 2022

This fixes a crash involving ZTS and dl().

In ZTS, the global registered_zend_ini_directives is copied to a thread-specific EG(ini_entries). Extensions loaded with dl() register their ini entries in EG(ini_entries), however they unregister them from registered_zend_ini_directives, which has no effect and leaves the entries in EG(ini_entries). This leads to problems when destroying EG(ini_entries) later, because it references resources that are already freed.

This change ensures that MODULE_TEMPORARY modules will unregister their entries from EG(ini_entries).

I added a test extension specifically for the purpose of testing dl(). I could have used the zend_test for that, but I felt that with a dedicated extension it would be harder to accidentally nerf/no-op the tests.

@arnaud-lb arnaud-lb force-pushed the issue-8185 branch 2 times, most recently from 4e62576 to 31c303f Compare April 24, 2022 12:06
@arnaud-lb arnaud-lb changed the base branch from master to PHP-8.1 April 24, 2022 12:06
@cmb69
Copy link
Member

cmb69 commented Apr 27, 2022

This is supposed to fix #8185, I think.

@arnaud-lb arnaud-lb force-pushed the issue-8185 branch 4 times, most recently from e9c08ee to 45c10f5 Compare April 29, 2022 20:54
@arnaud-lb arnaud-lb marked this pull request as ready for review April 29, 2022 21:54
@arnaud-lb arnaud-lb requested review from cmb69 and Girgias April 29, 2022 21:54
Copy link
Member

@cmb69 cmb69 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR! Before more detailed review, we need to clarify whether this constitutes an ABI break (if so, we cannot target any of the stable PHP versions).

Copy link
Member

@cmb69 cmb69 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, this looks good to me, but I left some style nits.

@@ -0,0 +1,41 @@
*.lo
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need this file? Isn't that already handled by .gitignore in the root?

| obtain it through the world-wide-web, please send a note to |
| [email protected] so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should add yourself as author.

extern zend_module_entry dl_test_module_entry;
# define phpext_dl_test_ptr &dl_test_module_entry

# define PHP_DL_TEST_VERSION "0.1.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the point in having an own version for a bundled extension; consider to use PHP_VERSION instead of some hard-coded value.

// Check that the dl_test extension is built. We don't use the --EXTENSIONS--
// section because we want to load the extension with dl().

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer

Suggested change
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
if (PHP_OS_FAMILY === 'Windows') {

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$path = ini_get('extension_dir') . DIRECTORY_SEPARATOR . 'php_dl_test.dll';
} else {
$path = ini_get('extension_dir') . DIRECTORY_SEPARATOR . 'dl_test.so';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to cater to macOS which uses .dylib as far as I know?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked because I was not sure. The PHP build appears to generate .so files. The CI looks ok too (no mention of skipping or failing these tests).

--TEST--
dl(): Loaded extensions properly unregister their ini settings
--SKIPIF--
<?php include __DIR__ . "/../../../dl_test/tests/skip.inc";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I very much prefer to explicitly have the closing PHP tags in .phpt files, so that syntax highlighting works.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't they also required for another reason? But yes I agree adding the closing tags is better

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. The sections containing PHP code are extracted to temporary files, so closing tags are not strictly needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me personally it's because I like to be able to run tests quickly without invoking run-tests, by just doing php thetest.phpt

Copy link
Member

@Girgias Girgias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than the PHPT test changes LGTM

--TEST--
dl(): Loaded extensions properly unregister their ini settings
--SKIPIF--
<?php include __DIR__ . "/../../../dl_test/tests/skip.inc";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<?php include __DIR__ . "/../../../dl_test/tests/skip.inc";
<?php include dirname(__DIR__, 3) . "/dl_test/tests/skip.inc";

Might be 2, not sure of the top of my head.

--TEST--
dl(): Loaded extensions properly unregister their ini settings
--SKIPIF--
<?php include __DIR__ . "/../../../dl_test/tests/skip.inc";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't they also required for another reason? But yes I agree adding the closing tags is better

@@ -210,7 +211,10 @@ ZEND_API zend_result zend_register_ini_entries(const zend_ini_entry_def *ini_ent
* lead to death.
*/
if (directives != EG(ini_directives)) {
ZEND_ASSERT(module_type == MODULE_TEMPORARY);
Copy link
Member

@bukka bukka Oct 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arnaud-lb just stumbled on this when fixing FPM extension loading using php_admin_value[extension] . It actaully uses php_dl and initializes permanent module so this is actually not going to work so I had to remove this assertion in #12277 . FPM is single threaded so it should not impact this issue - it just really needs to remove the assertion.

There might be potentially other issues with using dl for permanent modules and it has got some limitation but think the whole concept of using php_dl in FPM is really problematic which will require some bigger changes in FPM to get it rif of it (introduction of pool manager).

Anyway if you see some bigger problem with my change, please comment on that PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants