Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 21 additions & 17 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
}

Expand Down
60 changes: 60 additions & 0 deletions ext/reflection/tests/gh21768.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
--TEST--
GH-21768: Assertion failure in ReflectionProperty::is{Readable,Writable}() on internal virtual properties
--EXTENSIONS--
dom
--FILE--
<?php

$rc = new ReflectionClass('DOMDocument');
foreach ($rc->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
Loading