Skip to content

Commit 8d12f66

Browse files
authored
Fix registration of internal readonly child classes (#15459)
Currently, internal classes are registered with the following code: INIT_CLASS_ENTRY(ce, "InternalClass", class_InternalClass_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ...; This has worked well so far, except if InternalClass is readonly. It is because some inheritance checks are run by zend_register_internal_class_ex before ZEND_ACC_READONLY_CLASS is added to ce_flags. The issue is fixed by adding a zend_register_internal_class_with_flags() zend API function that stubs can use from now on. This function makes sure to add the flags before running any checks. Since the new API is not available in lower PHP versions, gen_stub.php has to keep support for the existing API for PHP 8.3 and below.
1 parent 6351468 commit 8d12f66

File tree

96 files changed

+405
-446
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+405
-446
lines changed

Zend/zend_API.c

+9-3
Original file line numberDiff line numberDiff line change
@@ -3493,9 +3493,16 @@ static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class
34933493
*/
34943494
ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce) /* {{{ */
34953495
{
3496-
zend_class_entry *register_class;
3496+
return zend_register_internal_class_with_flags(class_entry, parent_ce, 0);
3497+
}
3498+
/* }}} */
34973499

3498-
register_class = zend_register_internal_class(class_entry);
3500+
ZEND_API zend_class_entry *zend_register_internal_class_with_flags(
3501+
zend_class_entry *class_entry,
3502+
zend_class_entry *parent_ce,
3503+
uint32_t ce_flags
3504+
) {
3505+
zend_class_entry *register_class = do_register_internal_class(class_entry, ce_flags);
34993506

35003507
if (parent_ce) {
35013508
zend_do_inheritance(register_class, parent_ce);
@@ -3504,7 +3511,6 @@ ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *cla
35043511

35053512
return register_class;
35063513
}
3507-
/* }}} */
35083514

35093515
ZEND_API void zend_class_implements(zend_class_entry *class_entry, int num_interfaces, ...) /* {{{ */
35103516
{

Zend/zend_API.h

+1
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ ZEND_API void zend_add_magic_method(zend_class_entry *ce, zend_function *fptr, z
390390

391391
ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *class_entry);
392392
ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce);
393+
ZEND_API zend_class_entry *zend_register_internal_class_with_flags(zend_class_entry *class_entry, zend_class_entry *parent_ce, uint32_t flags);
393394
ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *orig_class_entry);
394395
ZEND_API void zend_class_implements(zend_class_entry *class_entry, int num_interfaces, ...);
395396

Zend/zend_attributes_arginfo.h

+7-14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_builtin_functions_arginfo.h

+1-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_closures_arginfo.h

+1-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_exceptions_arginfo.h

+12-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_fibers_arginfo.h

+2-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_generators_arginfo.h

+2-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_interfaces_arginfo.h

+1-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_weakrefs_arginfo.h

+2-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/gen_stub.php

+25-4
Original file line numberDiff line numberDiff line change
@@ -3274,11 +3274,18 @@ public function getRegistration(array $allConstInfos): string
32743274
$code .= "static zend_class_entry *register_class_$escapedName(" . (empty($params) ? "void" : implode(", ", $params)) . ")\n";
32753275

32763276
$code .= "{\n";
3277+
3278+
$flagCodes = generateVersionDependentFlagCode("%s", $this->getFlagsByPhpVersion(), $this->phpVersionIdMinimumCompatibility);
3279+
$flags = implode("", $flagCodes);
3280+
32773281
if ($this->type === "enum") {
32783282
$name = addslashes((string) $this->name);
32793283
$backingType = $this->enumBackingType
32803284
? $this->enumBackingType->toTypeCode() : "IS_UNDEF";
32813285
$code .= "\tzend_class_entry *class_entry = zend_register_internal_enum(\"$name\", $backingType, class_{$escapedName}_methods);\n";
3286+
if ($flags !== "") {
3287+
$code .= "\tclass_entry->ce_flags |= $flags\n";
3288+
}
32823289
} else {
32833290
$code .= "\tzend_class_entry ce, *class_entry;\n\n";
32843291
if (count($this->name->getParts()) > 1) {
@@ -3291,15 +3298,29 @@ public function getRegistration(array $allConstInfos): string
32913298
}
32923299

32933300
if ($this->type === "class" || $this->type === "trait") {
3294-
$code .= "\tclass_entry = zend_register_internal_class_ex(&ce, " . (isset($this->extends[0]) ? "class_entry_" . str_replace("\\", "_", $this->extends[0]->toString()) : "NULL") . ");\n";
3301+
if (!$php84MinimumCompatibility) {
3302+
$code .= "#if (PHP_VERSION_ID >= " . PHP_84_VERSION_ID . ")\n";
3303+
}
3304+
3305+
$code .= "\tclass_entry = zend_register_internal_class_with_flags(&ce, " . (isset($this->extends[0]) ? "class_entry_" . str_replace("\\", "_", $this->extends[0]->toString()) : "NULL") . ", " . ($flags ?: 0) . ");\n";
3306+
3307+
if (!$php84MinimumCompatibility) {
3308+
$code .= "#else\n";
3309+
3310+
$code .= "\tclass_entry = zend_register_internal_class_ex(&ce, " . (isset($this->extends[0]) ? "class_entry_" . str_replace("\\", "_", $this->extends[0]->toString()) : "NULL") . ");\n";
3311+
if ($flags !== "") {
3312+
$code .= "\tclass_entry->ce_flags |= $flags;\n";
3313+
}
3314+
$code .= "#endif\n";
3315+
}
32953316
} else {
32963317
$code .= "\tclass_entry = zend_register_internal_interface(&ce);\n";
3318+
if ($flags !== "") {
3319+
$code .= "\tclass_entry->ce_flags |= $flags\n";
3320+
}
32973321
}
32983322
}
32993323

3300-
$flagCodes = generateVersionDependentFlagCode("\tclass_entry->ce_flags |= %s;\n", $this->getFlagsByPhpVersion(), $this->phpVersionIdMinimumCompatibility);
3301-
$code .= implode("", $flagCodes);
3302-
33033324
if ($this->exposedDocComment) {
33043325
if (!$php84MinimumCompatibility) {
33053326
$code .= "#if (PHP_VERSION_ID >= " . PHP_84_VERSION_ID . ")\n";

0 commit comments

Comments
 (0)