Fix unregistering ini entries of dynamically loaded extension (#8435)

Fixes GH-8185
This commit is contained in:
Arnaud Le Blanc 2022-05-06 15:25:44 +02:00 committed by GitHub
parent b2be88954b
commit f07a08df5c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 408 additions and 14 deletions

View file

@ -14,7 +14,7 @@ task:
- pkg install -y autoconf bison gmake re2c icu libiconv png freetype2 enchant2 bzip2 krb5 t1lib gmp tidyp libsodium libzip libxml2 libxslt openssl oniguruma pkgconf webp libavif
script:
- ./buildconf -f
- ./configure --prefix=/usr/local --enable-debug --enable-option-checking=fatal --enable-fpm --with-pdo-sqlite --without-pear --with-bz2 --with-avif --with-jpeg --with-webp --with-freetype --enable-gd --enable-exif --with-zip --with-zlib --enable-soap --enable-xmlreader --with-xsl --with-libxml --enable-shmop --enable-pcntl --enable-mbstring --with-curl --enable-sockets --with-openssl --with-iconv=/usr/local --enable-bcmath --enable-calendar --enable-ftp --with-kerberos --with-ffi --enable-zend-test --enable-intl --with-mhash --with-sodium --enable-werror --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d
- ./configure --prefix=/usr/local --enable-debug --enable-option-checking=fatal --enable-fpm --with-pdo-sqlite --without-pear --with-bz2 --with-avif --with-jpeg --with-webp --with-freetype --enable-gd --enable-exif --with-zip --with-zlib --enable-soap --enable-xmlreader --with-xsl --with-libxml --enable-shmop --enable-pcntl --enable-mbstring --with-curl --enable-sockets --with-openssl --with-iconv=/usr/local --enable-bcmath --enable-calendar --enable-ftp --with-kerberos --with-ffi --enable-zend-test --enable-dl-test=shared --enable-intl --with-mhash --with-sodium --enable-werror --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d
- gmake -j2
- mkdir /etc/php.d
- gmake install

View file

@ -61,6 +61,7 @@ runs:
--enable-sysvmsg \
--with-ffi \
--enable-zend-test \
--enable-dl-test=shared \
--enable-intl \
--with-mhash \
--with-sodium \

View file

@ -56,6 +56,7 @@ runs:
--enable-sysvmsg \
--with-ffi \
--enable-zend-test \
--enable-dl-test=shared \
--with-ldap \
--with-ldap-sasl \
--with-password-argon2 \

View file

@ -1033,9 +1033,7 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */
void zend_register_standard_ini_entries(void) /* {{{ */
{
int module_number = 0;
REGISTER_INI_ENTRIES();
zend_register_ini_entries_ex(ini_entries, 0, MODULE_PERSISTENT);
}
/* }}} */

View file

@ -2965,7 +2965,7 @@ void module_destructor(zend_module_entry *module) /* {{{ */
if (module->module_started
&& !module->module_shutdown_func
&& module->type == MODULE_TEMPORARY) {
zend_unregister_ini_entries(module->module_number);
zend_unregister_ini_entries_ex(module->module_number, module->type);
}
/* Deinitialize module globals */

View file

@ -23,6 +23,7 @@
#include "zend_alloc.h"
#include "zend_operators.h"
#include "zend_strtod.h"
#include "zend_modules.h"
static HashTable *registered_zend_ini_directives;
@ -194,7 +195,7 @@ ZEND_API void zend_ini_sort_entries(void) /* {{{ */
/*
* Registration / unregistration
*/
ZEND_API zend_result zend_register_ini_entries(const zend_ini_entry_def *ini_entry, int module_number) /* {{{ */
ZEND_API zend_result zend_register_ini_entries_ex(const zend_ini_entry_def *ini_entry, int module_number, int module_type) /* {{{ */
{
zend_ini_entry *p;
zval *default_value;
@ -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);
directives = EG(ini_directives);
} else {
ZEND_ASSERT(module_type == MODULE_PERSISTENT);
}
#endif
@ -234,7 +238,7 @@ ZEND_API zend_result zend_register_ini_entries(const zend_ini_entry_def *ini_ent
if (p->name) {
zend_string_release_ex(p->name, 1);
}
zend_unregister_ini_entries(module_number);
zend_unregister_ini_entries_ex(module_number, module_type);
return FAILURE;
}
if (((default_value = zend_get_configuration_directive(p->name)) != NULL) &&
@ -255,9 +259,46 @@ ZEND_API zend_result zend_register_ini_entries(const zend_ini_entry_def *ini_ent
}
/* }}} */
ZEND_API zend_result zend_register_ini_entries(const zend_ini_entry_def *ini_entry, int module_number) /* {{{ */
{
zend_module_entry *module;
/* Module is likely to be the last one in the list */
ZEND_HASH_REVERSE_FOREACH_PTR(&module_registry, module) {
if (module->module_number == module_number) {
return zend_register_ini_entries_ex(ini_entry, module_number, module->type);
}
} ZEND_HASH_FOREACH_END();
return FAILURE;
}
/* }}} */
ZEND_API void zend_unregister_ini_entries_ex(int module_number, int module_type) /* {{{ */
{
static HashTable *ini_directives;
if (module_type == MODULE_TEMPORARY) {
ini_directives = EG(ini_directives);
} else {
ini_directives = registered_zend_ini_directives;
}
zend_hash_apply_with_argument(ini_directives, zend_remove_ini_entries, (void *) &module_number);
}
/* }}} */
ZEND_API void zend_unregister_ini_entries(int module_number) /* {{{ */
{
zend_hash_apply_with_argument(registered_zend_ini_directives, zend_remove_ini_entries, (void *) &module_number);
zend_module_entry *module;
/* Module is likely to be the last one in the list */
ZEND_HASH_REVERSE_FOREACH_PTR(&module_registry, module) {
if (module->module_number == module_number) {
zend_unregister_ini_entries_ex(module_number, module->type);
return;
}
} ZEND_HASH_FOREACH_END();
}
/* }}} */

View file

@ -72,7 +72,9 @@ ZEND_API void zend_copy_ini_directives(void);
ZEND_API void zend_ini_sort_entries(void);
ZEND_API zend_result zend_register_ini_entries(const zend_ini_entry_def *ini_entry, int module_number);
ZEND_API zend_result zend_register_ini_entries_ex(const zend_ini_entry_def *ini_entry, int module_number, int module_type);
ZEND_API void zend_unregister_ini_entries(int module_number);
ZEND_API void zend_unregister_ini_entries_ex(int module_number, int module_type);
ZEND_API void zend_ini_refresh_caches(int stage);
ZEND_API zend_result zend_alter_ini_entry(zend_string *name, zend_string *new_value, int modify_type, int stage);
ZEND_API zend_result zend_alter_ini_entry_ex(zend_string *name, zend_string *new_value, int modify_type, int stage, bool force_change);

View file

@ -50,6 +50,7 @@ steps:
--enable-sysvmsg \
--with-ffi \
--enable-zend-test \
--enable-dl-test=shared \
--with-ldap \
--with-ldap-sasl \
--with-password-argon2 \

View file

@ -62,6 +62,7 @@ jobs:
--enable-sysvmsg \
--with-ffi \
--enable-zend-test \
--enable-dl-test=shared \
--with-mhash \
--with-sodium \
--enable-dba \

View file

@ -49,6 +49,7 @@ jobs:
--enable-calendar \
--enable-ftp \
--enable-zend-test \
--enable-dl-test=shared \
--enable-werror \
--enable-memory-sanitizer \
--with-config-file-path=/etc \

View file

@ -75,7 +75,10 @@ PHP_TEST_SETTINGS = -d 'open_basedir=' -d 'output_buffering=0' -d 'memory_limit=
PHP_TEST_SHARED_EXTENSIONS = ` \
if test "x$(PHP_MODULES)" != "x"; then \
for i in $(PHP_MODULES)""; do \
. $$i; $(top_srcdir)/build/shtool echo -n -- " -d extension=$$dlname"; \
. $$i; \
if test "x$$dlname" != "xdl_test.so"; then \
$(top_srcdir)/build/shtool echo -n -- " -d extension=$$dlname"; \
fi; \
done; \
fi; \
if test "x$(PHP_ZEND_EX)" != "x"; then \

8
ext/dl_test/config.m4 Normal file
View file

@ -0,0 +1,8 @@
PHP_ARG_ENABLE([dl-test],
[whether to enable dl-test extension],
[AS_HELP_STRING([--enable-dl-test],
[Enable dl_test extension])])
if test "$PHP_DL_TEST" != "no"; then
PHP_NEW_EXTENSION(dl_test, dl_test.c, [shared],, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
fi

8
ext/dl_test/config.w32 Normal file
View file

@ -0,0 +1,8 @@
// vim:ft=javascript
ARG_ENABLE("dl-test", "enable dl_test extension", "no");
if (PHP_DL_TEST != "no") {
EXTENSION("dl_test", "dl_test.c", true, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
ADD_FLAG("CFLAGS_DL_TEST", "/D PHP_DL_TEST_EXPORTS ");
}

146
ext/dl_test/dl_test.c Normal file
View file

@ -0,0 +1,146 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Arnaud Le Blanc <arnaud.lb@gmail.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "php.h"
#include "ext/standard/info.h"
#include "php_dl_test.h"
#include "dl_test_arginfo.h"
ZEND_DECLARE_MODULE_GLOBALS(dl_test)
/* {{{ void dl_test_test1() */
PHP_FUNCTION(dl_test_test1)
{
ZEND_PARSE_PARAMETERS_NONE();
php_printf("The extension %s is loaded and working!\r\n", "dl_test");
}
/* }}} */
/* {{{ string dl_test_test2( [ string $var ] ) */
PHP_FUNCTION(dl_test_test2)
{
char *var = "World";
size_t var_len = sizeof("World") - 1;
zend_string *retval;
ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_STRING(var, var_len)
ZEND_PARSE_PARAMETERS_END();
retval = strpprintf(0, "Hello %s", var);
RETURN_STR(retval);
}
/* }}}*/
/* {{{ INI */
PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN("dl_test.long", "0", PHP_INI_ALL, OnUpdateLong, long_value, zend_dl_test_globals, dl_test_globals)
STD_PHP_INI_ENTRY("dl_test.string", "hello", PHP_INI_ALL, OnUpdateString, string_value, zend_dl_test_globals, dl_test_globals)
PHP_INI_END()
/* }}} */
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(dl_test)
{
/* Test backwards compatibility */
if (getenv("PHP_DL_TEST_USE_OLD_REGISTER_INI_ENTRIES")) {
zend_register_ini_entries(ini_entries, module_number);
} else {
REGISTER_INI_ENTRIES();
}
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION */
static PHP_MSHUTDOWN_FUNCTION(dl_test)
{
/* Test backwards compatibility */
if (getenv("PHP_DL_TEST_USE_OLD_REGISTER_INI_ENTRIES")) {
zend_unregister_ini_entries(module_number);
} else {
UNREGISTER_INI_ENTRIES();
}
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RINIT_FUNCTION */
PHP_RINIT_FUNCTION(dl_test)
{
#if defined(ZTS) && defined(COMPILE_DL_DL_TEST)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(dl_test)
{
php_info_print_table_start();
php_info_print_table_header(2, "dl_test support", "enabled");
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* }}} */
/* {{{ PHP_GINIT_FUNCTION */
static PHP_GINIT_FUNCTION(dl_test)
{
#if defined(COMPILE_DL_DL_TEST) && defined(ZTS)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
memset(dl_test_globals, 0, sizeof(*dl_test_globals));
}
/* }}} */
/* {{{ dl_test_module_entry */
zend_module_entry dl_test_module_entry = {
STANDARD_MODULE_HEADER,
"dl_test",
ext_functions,
PHP_MINIT(dl_test),
PHP_MSHUTDOWN(dl_test),
PHP_RINIT(dl_test),
NULL,
PHP_MINFO(dl_test),
PHP_DL_TEST_VERSION,
PHP_MODULE_GLOBALS(dl_test),
PHP_GINIT(dl_test),
NULL,
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */
#ifdef COMPILE_DL_DL_TEST
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
# endif
ZEND_GET_MODULE(dl_test)
#endif

View file

@ -0,0 +1,7 @@
<?php
/** @generate-class-entries */
function dl_test_test1(): void {}
function dl_test_test2(string $str = ""): string {}

View file

@ -0,0 +1,20 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 39ccf8141b0eb785cafd490b420f2e99d6a7a66d */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dl_test_test1, 0, 0, IS_VOID, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dl_test_test2, 0, 0, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, str, IS_STRING, 0, "\"\"")
ZEND_END_ARG_INFO()
ZEND_FUNCTION(dl_test_test1);
ZEND_FUNCTION(dl_test_test2);
static const zend_function_entry ext_functions[] = {
ZEND_FE(dl_test_test1, arginfo_dl_test_test1)
ZEND_FE(dl_test_test2, arginfo_dl_test_test2)
ZEND_FE_END
};

36
ext/dl_test/php_dl_test.h Normal file
View file

@ -0,0 +1,36 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: |
+----------------------------------------------------------------------+
*/
#ifndef PHP_DL_TEST_H
# define PHP_DL_TEST_H
extern zend_module_entry dl_test_module_entry;
# define phpext_dl_test_ptr &dl_test_module_entry
# define PHP_DL_TEST_VERSION PHP_VERSION
# if defined(ZTS) && defined(COMPILE_DL_DL_TEST)
ZEND_TSRMLS_CACHE_EXTERN()
# endif
ZEND_BEGIN_MODULE_GLOBALS(dl_test)
zend_long long_value;
char *string_value;
ZEND_END_MODULE_GLOBALS(dl_test);
#define DT_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(dl_test, v)
#endif /* PHP_DL_TEST_H */

View file

@ -0,0 +1,14 @@
<?php
// 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 (PHP_OS_FAMILY === 'Windows') {
$path = ini_get('extension_dir') . DIRECTORY_SEPARATOR . 'php_dl_test.dll';
} else {
$path = ini_get('extension_dir') . DIRECTORY_SEPARATOR . 'dl_test.so';
}
if (!file_exists($path)) {
die(sprintf('skip dl_test extension is not built (tried %s)', $path));
}

View file

@ -0,0 +1,34 @@
--TEST--
dl(): Loaded extensions properly unregister their ini settings
--SKIPIF--
<?php include dirname(__DIR__, 3) . "/dl_test/tests/skip.inc"; ?>
--FILE--
<?php
if (extension_loaded('dl_test')) {
exit('Error: dl_test is already loaded');
}
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$loaded = dl('php_dl_test.dll');
} else {
$loaded = dl('dl_test.so');
}
var_dump($loaded);
dl_test_test1();
var_dump(dl_test_test2("World!"));
// ini_get() gets optimized out, so we use ini_get_all() here
var_dump(ini_get_all()["dl_test.long"]["local_value"]);
var_dump(ini_get_all()["dl_test.string"]["local_value"]);
echo "OK\n";
--EXPECT--
bool(true)
The extension dl_test is loaded and working!
string(12) "Hello World!"
string(1) "0"
string(5) "hello"
OK

View file

@ -0,0 +1,35 @@
--TEST--
dl(): Extensions compiled against zend_register_ini_entries() are supported
--ENV--
PHP_DL_TEST_USE_OLD_REGISTER_INI_ENTRIES=1
--SKIPIF--
<?php include dirname(__DIR__, 3) . "/dl_test/tests/skip.inc"; ?>
--FILE--
<?php
if (extension_loaded('dl_test')) {
exit('Error: dl_test is already loaded');
}
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$loaded = dl('php_dl_test.dll');
} else {
$loaded = dl('dl_test.so');
}
var_dump($loaded);
dl_test_test1();
var_dump(dl_test_test2("World!"));
// ini_get() gets optimized out, so we use ini_get_all() here
var_dump(ini_get_all()["dl_test.long"]["local_value"]);
var_dump(ini_get_all()["dl_test.string"]["local_value"]);
echo "OK\n";
--EXPECT--
bool(true)
The extension dl_test is loaded and working!
string(12) "Hello World!"
string(1) "0"
string(5) "hello"
OK

View file

@ -0,0 +1,36 @@
--TEST--
dl(): Loaded extensions support ini_set()
--SKIPIF--
<?php include dirname(__DIR__, 3) . "/dl_test/tests/skip.inc"; ?>
--FILE--
<?php
if (extension_loaded('dl_test')) {
exit('Error: dl_test is already loaded');
}
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$loaded = dl('php_dl_test.dll');
} else {
$loaded = dl('dl_test.so');
}
var_dump($loaded);
dl_test_test1();
var_dump(dl_test_test2("World!"));
ini_set("dl_test.long", "1");
ini_set("dl_test.string", "world");
// ini_get() gets optimized out, so we use ini_get_all() here
var_dump(ini_get_all()["dl_test.long"]["local_value"]);
var_dump(ini_get_all()["dl_test.string"]["local_value"]);
echo "OK\n";
--EXPECT--
bool(true)
The extension dl_test is loaded and working!
string(12) "Hello World!"
string(1) "1"
string(5) "world"
OK

View file

@ -2016,7 +2016,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
{
zend_utility_functions zuf;
zend_utility_values zuv;
int retval = SUCCESS, module_number=0; /* for REGISTER_INI_ENTRIES() */
int retval = SUCCESS, module_number=0;
char *php_os;
zend_module_entry *module;
@ -2194,7 +2194,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
zend_stream_shutdown();
/* Register PHP core ini entries */
REGISTER_INI_ENTRIES();
zend_register_ini_entries_ex(ini_entries, module_number, MODULE_PERSISTENT);
/* Register Zend ini entries */
zend_register_standard_ini_entries();
@ -2278,7 +2278,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
module->version = PHP_VERSION;
module->info_func = PHP_MINFO(php_core);
}
/* freeze the list of observer fcall_init handlers */
zend_observer_post_startup();
@ -2389,7 +2389,7 @@ int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals)
/* {{{ php_module_shutdown */
void php_module_shutdown(void)
{
int module_number=0; /* for UNREGISTER_INI_ENTRIES() */
int module_number=0;
module_shutdown = 1;
@ -2420,7 +2420,7 @@ void php_module_shutdown(void)
/* Destroys filter & transport registries too */
php_shutdown_stream_wrappers(module_number);
UNREGISTER_INI_ENTRIES();
zend_unregister_ini_entries_ex(module_number, MODULE_PERSISTENT);
/* close down the ini config */
php_shutdown_config();

View file

@ -68,6 +68,7 @@ $S390X_CONFIG \
--with-ffi \
--with-sodium \
--enable-zend-test=shared \
--enable-dl-test=shared \
--enable-werror \
--with-pear