Stop DOM nodes from claiming inherited members as own properties - #112
Merged
Merged
Conversation
lahma
force-pushed
the
fix/dom-node-own-properties
branch
from
July 26, 2026 19:08
a661c1f to
0984060
Compare
`DomNodeInstance.GetOwnProperty` falls back to returning the prototype's
descriptor when the node has no own property of that name. `[[GetOwnProperty]]`
is not supposed to look past the object itself, so a node ends up disagreeing
with itself:
document.body.hasOwnProperty('firstChild') // true
Object.getOwnPropertyDescriptor(b, 'firstChild') // an accessor
Object.getOwnPropertyNames(document.body) // []
Object.keys(document.body) // []
Library code that feature-detects with `hasOwnProperty` before walking the
prototype chain gets the wrong answer, and anything that pairs
`getOwnPropertyNames` with `getOwnPropertyDescriptor` sees an object whose keys
and descriptors do not agree.
Drop the fallback. An indexer is the only thing that can legitimately produce an
own property here, so that probe stays; everything else is a member of the DOM
interface, lives on the prototype, and is found by the engine's ordinary
own -> prototype lookup. Reads, writes, method calls and `in` are unaffected -
only the "is this mine?" answer changes.
As a side effect the node stops answering the prototype's own-property probe on
behalf of the prototype, which is what lets an engine cache a prototype lookup:
such caches only engage once the receiver genuinely reports no own property.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0179sA2T7HuRfRfSc2JirFik
lahma
force-pushed
the
fix/dom-node-own-properties
branch
from
July 26, 2026 20:33
0984060 to
ef497c2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
DomNodeInstance.GetOwnPropertyfalls back to returning the prototype's descriptor when the node has no own property of that name.[[GetOwnProperty]]is not supposed to look past the object itself, so a node ends up disagreeing with itself:Library code that feature-detects with
hasOwnPropertybefore walking the prototype chain gets the wrong answer, and anything that pairsgetOwnPropertyNameswithgetOwnPropertyDescriptorsees an object whose keys and descriptors do not agree.Change
Drop the fallback. An indexer is the only thing that can legitimately produce an own property here, so that probe stays; everything else is a member of the DOM interface, lives on the prototype, and is found by the engine's ordinary own -> prototype lookup.
Reads, writes, method calls and
inare unaffected - only the "is this mine?" answer changes.Effect on member lookup
This started as a correctness fix, and on the Jint version the branch was written against that is all it was. Now that #120 has moved the project to Jint 4.14.0, the change has a second, mechanical consequence worth recording. Both points below are read off the engine's code path; nothing here has been measured.
JintMemberExpressionresolvesnode.memberby first asking the receiver whether it has an own property of that name.ObjectInstance.Get. Each run walks to the prototype and asks it for the descriptor. Without the fallback the first question misses cheaply and the engine resolves the member on the prototype itself, so the second walk is gone.Neither point is the reason for the change; the own-property answer being wrong is. They are noted because the version bump quietly turned a neutral change into a mildly beneficial one.
Tests
DomTests.InheritedMemberIsNotAnOwnPropertyOfTheNodefails ondeveland passes here. Three further tests pin the behaviour that must not change: the member is still visible through the prototype, an inherited accessor still reads and writes, and a property assigned from script is still reported by bothhasOwnPropertyandgetOwnPropertyNames.I also diffed the full own-property name set and
Symbol.toStringTagof every prototype in the chain of ten different DOM object kinds, plus the global object, before and after: byte-identical. That comparison was re-run against the currentdevel, since #117 changed when prototype members get registered.Rebased onto current
devel. The suite is green onnet8.0,net462andnet472- 131 tests ondevel, 135 here.🤖 Generated with Claude Code
https://claude.ai/code/session_0179sA2T7HuRfRfSc2JirFik