diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 7552b00c1151..5bdd5e18bf22 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6742,8 +6742,7 @@ ZEND_METHOD(ReflectionProperty, isReadable) RETURN_FALSE; } - if (prop->flags & ZEND_ACC_VIRTUAL) { - ZEND_ASSERT(prop->hooks); + if ((prop->flags & ZEND_ACC_VIRTUAL) && prop->hooks) { if (!prop->hooks[ZEND_PROPERTY_HOOK_GET]) { RETURN_FALSE; } @@ -6835,26 +6834,31 @@ ZEND_METHOD(ReflectionProperty, isWritable) RETURN_FALSE; } - if (prop->flags & ZEND_ACC_VIRTUAL) { - ZEND_ASSERT(prop->hooks); + if ((prop->flags & ZEND_ACC_VIRTUAL) && prop->hooks) { if (!prop->hooks[ZEND_PROPERTY_HOOK_SET]) { RETURN_FALSE; } - } else if (obj && (prop->flags & ZEND_ACC_READONLY)) { + } else if (prop->flags & ZEND_ACC_VIRTUAL) { + if (prop->flags & ZEND_ACC_READONLY) { + RETURN_FALSE; + } + } else if ((prop->flags & ZEND_ACC_READONLY)) { + if (obj) { retry:; - zval *prop_val = OBJ_PROP(obj, prop->offset); - if (Z_TYPE_P(prop_val) == IS_UNDEF - && zend_lazy_object_must_init(obj) - && (Z_PROP_FLAG_P(prop_val) & IS_PROP_LAZY) - ) { - obj = zend_lazy_object_init(obj); - if (!obj) { - RETURN_THROWS(); + zval *prop_val = OBJ_PROP(obj, prop->offset); + if (Z_TYPE_P(prop_val) == IS_UNDEF + && zend_lazy_object_must_init(obj) + && (Z_PROP_FLAG_P(prop_val) & IS_PROP_LAZY) + ) { + obj = zend_lazy_object_init(obj); + if (!obj) { + RETURN_THROWS(); + } + goto retry; + } + if (Z_TYPE_P(prop_val) != IS_UNDEF && !(Z_PROP_FLAG_P(prop_val) & IS_PROP_REINITABLE)) { + RETURN_FALSE; } - goto retry; - } - if (Z_TYPE_P(prop_val) != IS_UNDEF && !(Z_PROP_FLAG_P(prop_val) & IS_PROP_REINITABLE)) { - RETURN_FALSE; } } diff --git a/ext/reflection/tests/gh21768.phpt b/ext/reflection/tests/gh21768.phpt new file mode 100644 index 000000000000..eabc7f89f123 --- /dev/null +++ b/ext/reflection/tests/gh21768.phpt @@ -0,0 +1,60 @@ +--TEST-- +GH-21768: Assertion failure in ReflectionProperty::is{Readable,Writable}() on internal virtual properties +--EXTENSIONS-- +dom +--FILE-- +getProperties() as $rp) { + if (!$rp->isVirtual()) { + continue; + } + echo $rp->getName(), ': readable=', var_export($rp->isReadable(null), true), + ', writable=', var_export($rp->isWritable(null), true), PHP_EOL; +} +echo "done", PHP_EOL; + +?> +--EXPECT-- +nodeName: readable=true, writable=false +nodeValue: readable=true, writable=true +nodeType: readable=true, writable=false +parentNode: readable=true, writable=false +parentElement: readable=true, writable=false +childNodes: readable=true, writable=false +firstChild: readable=true, writable=false +lastChild: readable=true, writable=false +previousSibling: readable=true, writable=false +nextSibling: readable=true, writable=false +attributes: readable=true, writable=false +isConnected: readable=true, writable=false +ownerDocument: readable=true, writable=false +namespaceURI: readable=true, writable=false +prefix: readable=true, writable=true +localName: readable=true, writable=false +baseURI: readable=true, writable=false +textContent: readable=true, writable=true +doctype: readable=true, writable=false +implementation: readable=true, writable=false +documentElement: readable=true, writable=false +actualEncoding: readable=true, writable=false +encoding: readable=true, writable=true +xmlEncoding: readable=true, writable=false +standalone: readable=true, writable=true +xmlStandalone: readable=true, writable=true +version: readable=true, writable=true +xmlVersion: readable=true, writable=true +strictErrorChecking: readable=true, writable=true +documentURI: readable=true, writable=true +config: readable=true, writable=false +formatOutput: readable=true, writable=true +validateOnParse: readable=true, writable=true +resolveExternals: readable=true, writable=true +preserveWhiteSpace: readable=true, writable=true +recover: readable=true, writable=true +substituteEntities: readable=true, writable=true +firstElementChild: readable=true, writable=false +lastElementChild: readable=true, writable=false +childElementCount: readable=true, writable=false +done