Skip to content

Commit 02ded69

Browse files
committed
Implement GH-9826: Make class_alias() work with internal classes
We can't increase the refcount of internal classes during request time. We fix this issue by not increasing refcount for internal classes upon creating an alias and taking this into account during the destruction.
1 parent ff84598 commit 02ded69

File tree

6 files changed

+27
-16
lines changed

6 files changed

+27
-16
lines changed

UPGRADING

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ PHP 8.3 UPGRADE NOTES
5757
"full" => bool
5858
"buffer_size" => int
5959
See GH-9336
60+
. class_alias() now supports creating an alias of an internal class.
6061

6162
- MBString:
6263
. mb_strtolower, mb_strtotitle, and mb_convert_case implement conditional

UPGRADING.INTERNALS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ PHP 8.3 INTERNALS UPGRADE NOTES
3030
for C99 features have been removed and therefore macro definitions
3131
from php_config.h have disappeared. Do not use those feature
3232
macros.
33+
* Internal class aliases created during request time can now exist in
34+
the class table. zend_register_class_alias_ex() will not increase
35+
the refcount of such cases and the cleanup function takes this into
36+
account.
3337

3438
========================
3539
2. Build system changes

Zend/tests/class_alias_006.phpt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ Testing creation of alias to an internal class
33
--FILE--
44
<?php
55

6-
try {
7-
class_alias('stdclass', 'foo');
8-
} catch (ValueError $exception) {
9-
echo $exception->getMessage() . "\n";
10-
}
6+
class_alias('stdclass', 'foo');
7+
$foo = new foo();
8+
var_dump($foo);
119

1210
?>
1311
--EXPECT--
14-
class_alias(): Argument #1 ($class) must be a user-defined class name, internal class name given
12+
object(stdClass)#1 (0) {
13+
}

Zend/zend_API.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3296,7 +3296,11 @@ ZEND_API zend_result zend_register_class_alias_ex(const char *name, size_t name_
32963296
ret = zend_hash_add(CG(class_table), lcname, &zv);
32973297
zend_string_release_ex(lcname, 0);
32983298
if (ret) {
3299-
if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
3299+
/* We cannot increase the refcount of an internal class during request time.
3300+
* Only persistent internal classes, or user classes can increase the refcount.
3301+
* We will make sure to check for the non-persistent internal class case in destroy_zend_class().
3302+
*/
3303+
if (ce->type != ZEND_INTERNAL_CLASS && !(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
33003304
ce->refcount++;
33013305
}
33023306
// avoid notifying at MINIT time

Zend/zend_builtin_functions.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,16 +1074,11 @@ ZEND_FUNCTION(class_alias)
10741074
ce = zend_lookup_class_ex(class_name, NULL, !autoload ? ZEND_FETCH_CLASS_NO_AUTOLOAD : 0);
10751075

10761076
if (ce) {
1077-
if (ce->type == ZEND_USER_CLASS) {
1078-
if (zend_register_class_alias_ex(ZSTR_VAL(alias_name), ZSTR_LEN(alias_name), ce, 0) == SUCCESS) {
1079-
RETURN_TRUE;
1080-
} else {
1081-
zend_error(E_WARNING, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(alias_name));
1082-
RETURN_FALSE;
1083-
}
1077+
if (zend_register_class_alias_ex(ZSTR_VAL(alias_name), ZSTR_LEN(alias_name), ce, false) == SUCCESS) {
1078+
RETURN_TRUE;
10841079
} else {
1085-
zend_argument_value_error(1, "must be a user-defined class name, internal class name given");
1086-
RETURN_THROWS();
1080+
zend_error(E_WARNING, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(alias_name));
1081+
RETURN_FALSE;
10871082
}
10881083
} else {
10891084
zend_error(E_WARNING, "Class \"%s\" not found", ZSTR_VAL(class_name));

Zend/zend_opcode.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,12 @@ ZEND_API void destroy_zend_class(zval *zv)
301301
return;
302302
}
303303

304+
/* As we could not increase the refcount of an internal class during request time,
305+
* we have to check for this case here. */
306+
if (UNEXPECTED(ce->type == ZEND_INTERNAL_CLASS && Z_TYPE_INFO_P(zv) == IS_ALIAS_PTR)) {
307+
return;
308+
}
309+
304310
if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
305311
zend_class_constant *c;
306312
zval *p, *end;
@@ -323,6 +329,8 @@ ZEND_API void destroy_zend_class(zval *zv)
323329
return;
324330
}
325331

332+
ZEND_ASSERT(ce->refcount > 0);
333+
326334
if (--ce->refcount > 0) {
327335
return;
328336
}

0 commit comments

Comments
 (0)