Skip to content

Fix GH-21768: ext/reflection: assertion failure on internal virtual p…#21769

Draft
devnexen wants to merge 2 commits intophp:masterfrom
devnexen:gh21768
Draft

Fix GH-21768: ext/reflection: assertion failure on internal virtual p…#21769
devnexen wants to merge 2 commits intophp:masterfrom
devnexen:gh21768

Conversation

@devnexen
Copy link
Copy Markdown
Member

…roperties.

ReflectionProperty::isReadable() and isWritable() asserted prop->hooks being set whenever ZEND_ACC_VIRTUAL is set. Internal classes such as DOMDocument declare virtual properties backed by the object read/write handlers without hooks, tripping the assertion.

Assertion introduced in e4f727d.

…l properties.

ReflectionProperty::isReadable() and isWritable() asserted prop->hooks
being set whenever ZEND_ACC_VIRTUAL is set. Internal classes such as
DOMDocument declare virtual properties backed by the object read/write
handlers without hooks, tripping the assertion.

Assertion introduced in e4f727d.
@ndossche
Copy link
Copy Markdown
Member

ndossche commented Apr 16, 2026

So this solves the assertion failure. But I wonder what this new reflection method actually tests...

I.e. the following code will throw:

<?php
$dom = new DOMDocument;
$dom->doctype = null; // Error!

but it claims this property is writable:

<?php
$rc = new ReflectionClass($dom);
var_dump($rc->getProperty('doctype')->isWritable(null)); // bool(true)

@devnexen
Copy link
Copy Markdown
Member Author

Fair point, returning true for read-only props like doctype is misleading. I'm not sure what the right call is here.

Would it make more sense to fix this on the DOM side, giving these @virtual properties proper get-only hooks so reflection can answer correctly, rather than working
around it in reflection itself? Hooks were designed for this shape, and it'd also benefit anything else that introspects them. It's a bigger patch, but probably the
more correct direction.

As a narrow alternative for the crash-fix, we could throw ReflectionException whenever the property is ZEND_ACC_VIRTUAL without hooks, something like "Cannot
determine writability of virtual property DOMDocument::$doctype without property hooks." Keeps the method honest (correct bool or "don't know") without pretending to
know.

Happy to go either way, or hold off on this PR if you'd rather sort it at the DOM level.

@ndossche
Copy link
Copy Markdown
Member

ndossche commented Apr 16, 2026

The properties of dom that aren't writable are marked as readonly. This isn't really right as some dom manipulations can change those properties indirectly anyway. This is a leftover from back in the days.
It would be more correct to redeclare them as private(set) instead of readonly, in conjunction with this patch. This might break property redeclarations though so that's definitely master-only material.

devnexen added a commit to devnexen/php-src that referenced this pull request Apr 16, 2026
@readonly on DOM property stubs was documentation only and did not
translate to any runtime flag, so reflection reported the properties
as writable while the write_property handler threw on assignment.
Declaring them public private(set) lets the engine reject external
writes via the normal visibility check and lets ReflectionProperty::
isWritable() answer honestly.

Also drops @readonly from the three non-virtual HTMLCollection
$children properties (Element, DocumentFragment, Document) and
applies private(set) there as well.

Depends on the assertion removal from phpGH-21769 for isReadable() to
stop aborting on these properties.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants