1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-18567: Preloading with internal class alias triggers assertion failure

The assertion is imprecise now, and the code assumed that from the
moment an internal class was encountered that there were only internal
classes remaining. This is wrong now, and we still have to continue if
we encounter an internal class. We can only skip the remaining iterations
if the entry in the hash table is not an alias.

Closes GH-18575.
This commit is contained in:
Niels Dossche
2025-05-16 21:12:17 +02:00
parent 92a0cc7d94
commit 41e11a627d
4 changed files with 61 additions and 5 deletions

2
NEWS
View File

@@ -32,6 +32,8 @@ PHP NEWS
- Opcache:
. Fixed bug GH-18417 (Windows SHM reattachment fails when increasing
memory_consumption or jit_buffer_size). (nielsdos)
. Fixed bug GH-18567 (Preloading with internal class alias triggers assertion
failure). (nielsdos)
- PDO_OCI:
. Fixed bug GH-18494 (PDO OCI segfault in statement GC). (nielsdos)

View File

@@ -3522,7 +3522,7 @@ static void preload_shutdown(void)
if (EG(class_table)) {
ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) {
zend_class_entry *ce = Z_PTR_P(zv);
if (ce->type == ZEND_INTERNAL_CLASS) {
if (ce->type == ZEND_INTERNAL_CLASS && Z_TYPE_P(zv) != IS_ALIAS_PTR) {
break;
}
} ZEND_HASH_MAP_FOREACH_END_DEL();
@@ -3610,7 +3610,15 @@ static void preload_move_user_classes(HashTable *src, HashTable *dst)
zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0);
ZEND_HASH_MAP_FOREACH_BUCKET_FROM(src, p, EG(persistent_classes_count)) {
zend_class_entry *ce = Z_PTR(p->val);
ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
/* Possible with internal class aliases */
if (ce->type == ZEND_INTERNAL_CLASS) {
ZEND_ASSERT(Z_TYPE(p->val) == IS_ALIAS_PTR);
_zend_hash_append(dst, p->key, &p->val);
zend_hash_del_bucket(src, p);
continue;
}
if (ce->info.user.filename != filename) {
filename = ce->info.user.filename;
if (filename) {
@@ -3904,7 +3912,12 @@ static void preload_link(void)
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(EG(class_table), key, zv, EG(persistent_classes_count)) {
ce = Z_PTR_P(zv);
ZEND_ASSERT(ce->type != ZEND_INTERNAL_CLASS);
/* Possible with internal class aliases */
if (ce->type == ZEND_INTERNAL_CLASS) {
ZEND_ASSERT(Z_TYPE_P(zv) == IS_ALIAS_PTR);
continue;
}
if (!(ce->ce_flags & (ZEND_ACC_TOP_LEVEL|ZEND_ACC_ANON_CLASS))
|| (ce->ce_flags & ZEND_ACC_LINKED)) {
@@ -3990,9 +4003,15 @@ static void preload_link(void)
ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) {
ce = Z_PTR_P(zv);
/* Possible with internal class aliases */
if (ce->type == ZEND_INTERNAL_CLASS) {
break;
if (Z_TYPE_P(zv) != IS_ALIAS_PTR) {
break; /* can stop already */
}
continue;
}
if ((ce->ce_flags & ZEND_ACC_LINKED) && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
if (!(ce->ce_flags & ZEND_ACC_TRAIT)) { /* don't update traits */
CG(in_compilation) = true; /* prevent autoloading */
@@ -4009,7 +4028,13 @@ static void preload_link(void)
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(
EG(class_table), key, zv, EG(persistent_classes_count)) {
ce = Z_PTR_P(zv);
ZEND_ASSERT(ce->type != ZEND_INTERNAL_CLASS);
/* Possible with internal class aliases */
if (ce->type == ZEND_INTERNAL_CLASS) {
ZEND_ASSERT(Z_TYPE_P(zv) == IS_ALIAS_PTR);
continue;
}
if ((ce->ce_flags & (ZEND_ACC_TOP_LEVEL|ZEND_ACC_ANON_CLASS))
&& !(ce->ce_flags & ZEND_ACC_LINKED)) {
zend_string *lcname = zend_string_tolower(ce->name);

View File

@@ -0,0 +1,27 @@
--TEST--
GH-18567 (Preloading with internal class alias triggers assertion failure)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.preload={PWD}/preload_gh18567.inc
--EXTENSIONS--
opcache
--SKIPIF--
<?php
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
?>
--FILE--
<?php
abstract class Test implements MyStringable {
}
$rc = new ReflectionClass(Test::class);
var_dump($rc->getInterfaces());
?>
--EXPECT--
array(1) {
["Stringable"]=>
object(ReflectionClass)#2 (1) {
["name"]=>
string(10) "Stringable"
}
}

View File

@@ -0,0 +1,2 @@
<?php
class_alias('Stringable', 'MyStringable');