Skip to content

Commit 4cf0f0e

Browse files
committed
Avoid allocating property slot for virtual properties
1 parent 1c4eb07 commit 4cf0f0e

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

Zend/zend_API.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4562,6 +4562,15 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z
45624562
}
45634563
}
45644564

4565+
/* Virtual properties have no backing storage, the offset should never be used. However, the
4566+
* virtual flag cannot be definitively determined at compile time. Allow using default values
4567+
* anyway, and assert after inheritance that the property is not actually virtual. */
4568+
if (access_type & ZEND_ACC_VIRTUAL) {
4569+
if (Z_TYPE_P(property) == IS_UNDEF) {
4570+
property_info->offset = (uint32_t)-1;
4571+
goto skip_property_storage;
4572+
}
4573+
}
45654574
if (access_type & ZEND_ACC_STATIC) {
45664575
if ((property_info_ptr = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) {
45674576
ZEND_ASSERT(property_info_ptr->flags & ZEND_ACC_STATIC);
@@ -4611,6 +4620,7 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z
46114620
ZVAL_COPY_VALUE(property_default_ptr, property);
46124621
Z_PROP_FLAG_P(property_default_ptr) = Z_ISUNDEF_P(property) ? IS_PROP_UNINIT : 0;
46134622
}
4623+
skip_property_storage:
46144624
if (ce->type & ZEND_INTERNAL_CLASS) {
46154625
/* Must be interned to avoid ZTS data races */
46164626
if (is_persistent_class(ce)) {

Zend/zend_inheritance.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,24 +1481,33 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke
14811481
/* If we added props to the child property, we use the childs slot for
14821482
* storage to keep the parent slot set to null. This automatically picks
14831483
* the slow path in the JIT. */
1484-
bool use_parent_prop = !parent_info->hooks && child_info->hooks;
1484+
bool use_child_prop = !parent_info->hooks && child_info->hooks;
1485+
1486+
if (use_child_prop && child_info->offset == ZEND_VIRTUAL_PROPERTY_OFFSET) {
1487+
child_info->offset = OBJ_PROP_TO_OFFSET(ce->default_properties_count);
1488+
ce->default_properties_count++;
1489+
ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1490+
zval *property_default_ptr = &ce->default_properties_table[OBJ_PROP_TO_NUM(child_info->offset)];
1491+
ZVAL_UNDEF(property_default_ptr);
1492+
Z_PROP_FLAG_P(property_default_ptr) = IS_PROP_UNINIT;
1493+
}
14851494

14861495
if (child_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
14871496
int parent_num = OBJ_PROP_TO_NUM(parent_info->offset);
14881497

14891498
/* Don't keep default properties in GC (they may be freed by opcache) */
14901499
zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
14911500

1492-
if (use_parent_prop) {
1501+
if (use_child_prop) {
1502+
ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1503+
} else {
14931504
int child_num = OBJ_PROP_TO_NUM(child_info->offset);
14941505
ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
14951506
ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1496-
} else {
1497-
ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
14981507
}
14991508
}
15001509

1501-
if (use_parent_prop) {
1510+
if (!use_child_prop) {
15021511
child_info->offset = parent_info->offset;
15031512
}
15041513
child_info->flags &= ~ZEND_ACC_VIRTUAL;

0 commit comments

Comments
 (0)