From c8cc23336dd7efb3ab0aac66326b1df9375556b6 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 15 Jul 2025 20:36:38 +0200 Subject: [PATCH] Fix properties_info_table for abstract properties Fixes GH-19053 Closes GH-19140 Co-authored-by: Bob Weinand --- NEWS | 2 ++ Zend/tests/gh19053.phpt | 26 ++++++++++++++++++++++++++ Zend/zend_inheritance.c | 19 +++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/gh19053.phpt diff --git a/NEWS b/NEWS index 0a4ceead58e..45bb77482fd 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ PHP NEWS - Core: . Fixed GH-19169 build issue with C++17 and ZEND_STATIC_ASSERT macro. (psumbera) + . Fixed bug GH-19053 (Duplicate property slot with hooks and interface + property). (ilutov) - Hash: . Fix crash on clone failure. (nielsdos) diff --git a/Zend/tests/gh19053.phpt b/Zend/tests/gh19053.phpt new file mode 100644 index 00000000000..7c82f1bc5f4 --- /dev/null +++ b/Zend/tests/gh19053.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-19053: Incorrect properties_info_table for abstract properties +--FILE-- + 2; } +} + +$c = new C; +var_dump($c); + +?> +--EXPECTF-- +object(C)#%d (0) { + ["foo"]=> + uninitialized(mixed) +} diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 6f399fbfec5..ced75ad82d9 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1687,10 +1687,25 @@ void zend_build_properties_info_table(zend_class_entry *ce) } } - ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop) { + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, zend_string *key, prop) { if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0 && !(prop->flags & ZEND_ACC_VIRTUAL)) { - uint32_t prop_table_offset = OBJ_PROP_TO_NUM(!(prop->prototype->flags & ZEND_ACC_VIRTUAL) ? prop->prototype->offset : prop->offset); + const zend_property_info *root_prop = prop->prototype; + if (UNEXPECTED(root_prop->flags & ZEND_ACC_VIRTUAL)) { + /* Prototype is virtual, we need to manually hunt down the first backed property. */ + root_prop = prop; + zend_class_entry *parent_ce; + while ((parent_ce = root_prop->ce->parent)) { + zend_property_info *parent_prop = zend_hash_find_ptr(&parent_ce->properties_info, key); + if (!parent_prop + || parent_prop->prototype != prop->prototype + || (parent_prop->flags & ZEND_ACC_VIRTUAL)) { + break; + } + root_prop = parent_prop; + } + } + uint32_t prop_table_offset = OBJ_PROP_TO_NUM(root_prop->offset); table[prop_table_offset] = prop; } } ZEND_HASH_FOREACH_END();