Merge branch 'PHP-8.4'

* PHP-8.4:
  Fix GH-18567: Preloading with internal class alias triggers assertion failure
This commit is contained in:
Niels Dossche 2025-05-19 19:20:16 +02:00
commit 94f5037ac3
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5
3 changed files with 59 additions and 5 deletions

View file

@ -3624,7 +3624,7 @@ static void preload_shutdown(void)
if (EG(class_table)) { if (EG(class_table)) {
ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) { ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) {
zend_class_entry *ce = Z_PTR_P(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; break;
} }
} ZEND_HASH_MAP_FOREACH_END_DEL(); } ZEND_HASH_MAP_FOREACH_END_DEL();
@ -3712,7 +3712,15 @@ static void preload_move_user_classes(HashTable *src, HashTable *dst)
zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0); zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0);
ZEND_HASH_MAP_FOREACH_BUCKET_FROM(src, p, EG(persistent_classes_count)) { ZEND_HASH_MAP_FOREACH_BUCKET_FROM(src, p, EG(persistent_classes_count)) {
zend_class_entry *ce = Z_PTR(p->val); 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) { if (ce->info.user.filename != filename) {
filename = ce->info.user.filename; filename = ce->info.user.filename;
if (filename) { if (filename) {
@ -4015,7 +4023,12 @@ static void preload_link(void)
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(EG(class_table), key, zv, EG(persistent_classes_count)) { ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(EG(class_table), key, zv, EG(persistent_classes_count)) {
ce = Z_PTR_P(zv); 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)) if (!(ce->ce_flags & (ZEND_ACC_TOP_LEVEL|ZEND_ACC_ANON_CLASS))
|| (ce->ce_flags & ZEND_ACC_LINKED)) { || (ce->ce_flags & ZEND_ACC_LINKED)) {
@ -4101,9 +4114,15 @@ static void preload_link(void)
ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) { ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) {
ce = Z_PTR_P(zv); ce = Z_PTR_P(zv);
/* Possible with internal class aliases */
if (ce->type == ZEND_INTERNAL_CLASS) { 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_LINKED) && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
if (!(ce->ce_flags & ZEND_ACC_TRAIT)) { /* don't update traits */ if (!(ce->ce_flags & ZEND_ACC_TRAIT)) { /* don't update traits */
CG(in_compilation) = true; /* prevent autoloading */ CG(in_compilation) = true; /* prevent autoloading */
@ -4120,7 +4139,13 @@ static void preload_link(void)
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM( ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(
EG(class_table), key, zv, EG(persistent_classes_count)) { EG(class_table), key, zv, EG(persistent_classes_count)) {
ce = Z_PTR_P(zv); 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)) if ((ce->ce_flags & (ZEND_ACC_TOP_LEVEL|ZEND_ACC_ANON_CLASS))
&& !(ce->ce_flags & ZEND_ACC_LINKED)) { && !(ce->ce_flags & ZEND_ACC_LINKED)) {
zend_string *lcname = zend_string_tolower(ce->name); 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');