diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index e3f7ca18151e5..47e0bc08bd5cc 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -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); diff --git a/ext/opcache/tests/gh18567.phpt b/ext/opcache/tests/gh18567.phpt new file mode 100644 index 0000000000000..e1d2a68af6775 --- /dev/null +++ b/ext/opcache/tests/gh18567.phpt @@ -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-- + +--FILE-- +getInterfaces()); +?> +--EXPECT-- +array(1) { + ["Stringable"]=> + object(ReflectionClass)#2 (1) { + ["name"]=> + string(10) "Stringable" + } +} diff --git a/ext/opcache/tests/preload_gh18567.inc b/ext/opcache/tests/preload_gh18567.inc new file mode 100644 index 0000000000000..d277e83f83be6 --- /dev/null +++ b/ext/opcache/tests/preload_gh18567.inc @@ -0,0 +1,2 @@ +