mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Destroy temporary module classes in reverse order
We destroy classes of dl()'ed modules in clean_module_classes(), during shutdown. Child classes of a module use structures of the parent class (such as inherited properties), which are destroyed earlier, so we have a use-after-free when destroying a child class. Here I destroy classes in reverse order, as it is done in zend_shutdown() for persistent classes. Fixes GH-17961 Fixes GH-15367
This commit is contained in:
6
NEWS
6
NEWS
@@ -2,6 +2,12 @@ PHP NEWS
|
||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
?? ??? ????, PHP 8.3.20
|
||||
|
||||
- Core:
|
||||
. Fixed bug GH-17961 (use-after-free during dl()'ed module class destruction).
|
||||
(Arnaud)
|
||||
. Fixed bug GH-15367 (dl() of module with aliased class crashes in shutdown).
|
||||
(Arnaud)
|
||||
|
||||
- DOM:
|
||||
. Fix weird unpack behaviour in DOM. (nielsdos)
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "zend.h"
|
||||
#include "zend_execute.h"
|
||||
#include "zend_API.h"
|
||||
#include "zend_hash.h"
|
||||
#include "zend_modules.h"
|
||||
#include "zend_extensions.h"
|
||||
#include "zend_constants.h"
|
||||
@@ -3111,21 +3112,17 @@ ZEND_API zend_result zend_get_module_started(const char *module_name) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int clean_module_class(zval *el, void *arg) /* {{{ */
|
||||
{
|
||||
zend_class_entry *ce = (zend_class_entry *)Z_PTR_P(el);
|
||||
int module_number = *(int *)arg;
|
||||
if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module->module_number == module_number) {
|
||||
return ZEND_HASH_APPLY_REMOVE;
|
||||
} else {
|
||||
return ZEND_HASH_APPLY_KEEP;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void clean_module_classes(int module_number) /* {{{ */
|
||||
{
|
||||
zend_hash_apply_with_argument(EG(class_table), clean_module_class, (void *) &module_number);
|
||||
/* Child classes may reuse structures from parent classes, so destroy in reverse order. */
|
||||
Bucket *bucket;
|
||||
ZEND_HASH_REVERSE_FOREACH_BUCKET(EG(class_table), bucket) {
|
||||
zend_class_entry *ce = Z_CE(bucket->val);
|
||||
if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module->module_number == module_number) {
|
||||
zend_hash_del_bucket(EG(class_table), bucket);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
@@ -92,10 +92,22 @@ PHP_METHOD(DlTest, test)
|
||||
RETURN_STR(retval);
|
||||
}
|
||||
|
||||
PHP_METHOD(DlTestSuperClass, test)
|
||||
{
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
RETURN_NULL();
|
||||
}
|
||||
|
||||
/* {{{ PHP_MINIT_FUNCTION */
|
||||
PHP_MINIT_FUNCTION(dl_test)
|
||||
{
|
||||
zend_class_entry *ce;
|
||||
|
||||
register_class_DlTest();
|
||||
ce = register_class_DlTestSuperClass();
|
||||
register_class_DlTestSubClass(ce);
|
||||
register_class_DlTestAliasedClass();
|
||||
|
||||
/* Test backwards compatibility */
|
||||
if (getenv("PHP_DL_TEST_USE_OLD_REGISTER_INI_ENTRIES")) {
|
||||
|
||||
@@ -12,3 +12,15 @@ function dl_test_test2(string $str = ""): string {}
|
||||
class DlTest {
|
||||
public function test(string $str = ""): string {}
|
||||
}
|
||||
|
||||
class DlTestSuperClass {
|
||||
public int $a;
|
||||
public function test(string $str = ""): string {}
|
||||
}
|
||||
|
||||
class DlTestSubClass extends DlTestSuperClass {
|
||||
}
|
||||
|
||||
/** @alias DlTestClassAlias */
|
||||
class DlTestAliasedClass {
|
||||
}
|
||||
|
||||
58
ext/dl_test/dl_test_arginfo.h
generated
58
ext/dl_test/dl_test_arginfo.h
generated
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 2dbacf5282b0f8e53923ac70495c2da43c7237e3 */
|
||||
* Stub hash: 0641a8eeff00e6c8083fe4a8639f970e3ba80db9 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dl_test_test1, 0, 0, IS_VOID, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
@@ -10,10 +10,13 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_DlTest_test arginfo_dl_test_test2
|
||||
|
||||
#define arginfo_class_DlTestSuperClass_test arginfo_dl_test_test2
|
||||
|
||||
|
||||
ZEND_FUNCTION(dl_test_test1);
|
||||
ZEND_FUNCTION(dl_test_test2);
|
||||
ZEND_METHOD(DlTest, test);
|
||||
ZEND_METHOD(DlTestSuperClass, test);
|
||||
|
||||
|
||||
static const zend_function_entry ext_functions[] = {
|
||||
@@ -28,6 +31,22 @@ static const zend_function_entry class_DlTest_methods[] = {
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
||||
static const zend_function_entry class_DlTestSuperClass_methods[] = {
|
||||
ZEND_ME(DlTestSuperClass, test, arginfo_class_DlTestSuperClass_test, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
||||
static const zend_function_entry class_DlTestSubClass_methods[] = {
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
||||
static const zend_function_entry class_DlTestAliasedClass_methods[] = {
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
static zend_class_entry *register_class_DlTest(void)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
@@ -37,3 +56,40 @@ static zend_class_entry *register_class_DlTest(void)
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
static zend_class_entry *register_class_DlTestSuperClass(void)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "DlTestSuperClass", class_DlTestSuperClass_methods);
|
||||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
|
||||
zval property_a_default_value;
|
||||
ZVAL_UNDEF(&property_a_default_value);
|
||||
zend_string *property_a_name = zend_string_init("a", sizeof("a") - 1, 1);
|
||||
zend_declare_typed_property(class_entry, property_a_name, &property_a_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
|
||||
zend_string_release(property_a_name);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
static zend_class_entry *register_class_DlTestSubClass(zend_class_entry *class_entry_DlTestSuperClass)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "DlTestSubClass", class_DlTestSubClass_methods);
|
||||
class_entry = zend_register_internal_class_ex(&ce, class_entry_DlTestSuperClass);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
static zend_class_entry *register_class_DlTestAliasedClass(void)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "DlTestAliasedClass", class_DlTestAliasedClass_methods);
|
||||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
zend_register_class_alias("DlTestClassAlias", class_entry);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user