Skip to content

Commit ad5432b

Browse files
committed
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.
1 parent 8e5b312 commit ad5432b

File tree

3 files changed

+59
-5
lines changed

3 files changed

+59
-5
lines changed

ext/opcache/ZendAccelerator.c

+30-5
Original file line numberDiff line numberDiff line change
@@ -3522,7 +3522,7 @@ static void preload_shutdown(void)
35223522
if (EG(class_table)) {
35233523
ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) {
35243524
zend_class_entry *ce = Z_PTR_P(zv);
3525-
if (ce->type == ZEND_INTERNAL_CLASS) {
3525+
if (ce->type == ZEND_INTERNAL_CLASS && Z_TYPE_P(zv) != IS_ALIAS_PTR) {
35263526
break;
35273527
}
35283528
} ZEND_HASH_MAP_FOREACH_END_DEL();
@@ -3610,7 +3610,14 @@ static void preload_move_user_classes(HashTable *src, HashTable *dst)
36103610
zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0);
36113611
ZEND_HASH_MAP_FOREACH_BUCKET_FROM(src, p, EG(persistent_classes_count)) {
36123612
zend_class_entry *ce = Z_PTR(p->val);
3613-
ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
3613+
3614+
/* Possible with internal class aliases */
3615+
if (ce->type == ZEND_INTERNAL_CLASS) {
3616+
_zend_hash_append(dst, p->key, &p->val);
3617+
zend_hash_del_bucket(src, p);
3618+
continue;
3619+
}
3620+
36143621
if (ce->info.user.filename != filename) {
36153622
filename = ce->info.user.filename;
36163623
if (filename) {
@@ -3904,7 +3911,11 @@ static void preload_link(void)
39043911

39053912
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(EG(class_table), key, zv, EG(persistent_classes_count)) {
39063913
ce = Z_PTR_P(zv);
3907-
ZEND_ASSERT(ce->type != ZEND_INTERNAL_CLASS);
3914+
3915+
/* Possible with internal class aliases */
3916+
if (ce->type == ZEND_INTERNAL_CLASS) {
3917+
continue;
3918+
}
39083919

39093920
if (!(ce->ce_flags & (ZEND_ACC_TOP_LEVEL|ZEND_ACC_ANON_CLASS))
39103921
|| (ce->ce_flags & ZEND_ACC_LINKED)) {
@@ -3990,9 +4001,15 @@ static void preload_link(void)
39904001

39914002
ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) {
39924003
ce = Z_PTR_P(zv);
4004+
4005+
/* Possible with internal class aliases */
39934006
if (ce->type == ZEND_INTERNAL_CLASS) {
3994-
break;
4007+
if (Z_TYPE_P(zv) != IS_ALIAS_PTR) {
4008+
break; /* can stop already */
4009+
}
4010+
continue;
39954011
}
4012+
39964013
if ((ce->ce_flags & ZEND_ACC_LINKED) && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
39974014
if (!(ce->ce_flags & ZEND_ACC_TRAIT)) { /* don't update traits */
39984015
CG(in_compilation) = true; /* prevent autoloading */
@@ -4009,7 +4026,15 @@ static void preload_link(void)
40094026
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(
40104027
EG(class_table), key, zv, EG(persistent_classes_count)) {
40114028
ce = Z_PTR_P(zv);
4012-
ZEND_ASSERT(ce->type != ZEND_INTERNAL_CLASS);
4029+
4030+
/* Possible with internal class aliases */
4031+
if (ce->type == ZEND_INTERNAL_CLASS) {
4032+
if (Z_TYPE_P(zv) != IS_ALIAS_PTR) {
4033+
break; /* can stop already */
4034+
}
4035+
continue;
4036+
}
4037+
40134038
if ((ce->ce_flags & (ZEND_ACC_TOP_LEVEL|ZEND_ACC_ANON_CLASS))
40144039
&& !(ce->ce_flags & ZEND_ACC_LINKED)) {
40154040
zend_string *lcname = zend_string_tolower(ce->name);

ext/opcache/tests/gh18567.phpt

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
GH-18567 (Preloading with internal class alias triggers assertion failure)
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.preload={PWD}/preload_gh18567.inc
7+
--EXTENSIONS--
8+
opcache
9+
--SKIPIF--
10+
<?php
11+
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
12+
?>
13+
--FILE--
14+
<?php
15+
abstract class Test implements MyStringable {
16+
}
17+
$rc = new ReflectionClass(Test::class);
18+
var_dump($rc->getInterfaces());
19+
?>
20+
--EXPECT--
21+
array(1) {
22+
["Stringable"]=>
23+
object(ReflectionClass)#2 (1) {
24+
["name"]=>
25+
string(10) "Stringable"
26+
}
27+
}

ext/opcache/tests/preload_gh18567.inc

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?php
2+
class_alias('Stringable', 'MyStringable');

0 commit comments

Comments
 (0)