Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Legacy platform object" getOwnPropertyDescriptor returns undefined when it should be finding dynamic properties #25036

Closed
pshaughn opened this issue Dec 3, 2019 · 11 comments

Comments

@pshaughn
Copy link
Member

@pshaughn pshaughn commented Dec 3, 2019

WebIDL/ecmascript-binding/legacy-platform-object.html tests out various things "legacy platform objects" (https://heycam.github.io/webidl/#es-legacy-platform-objects) are expected to do, most of which involving pretending to be arrays or open-ended hashmaps in one way or another. Mutliple tests fail on getOwnPropertyDescriptor, which is not seeing the dynamic properties.

HTMLSelectElement insufficiently pretending to be an array is also in #25003; there is possibly overlap, if the reason getOwnPropertyDescriptor isn't working is that the property isn't even there to get.

Other failures are DOMTokenList with numeric properties and DOMStringMap with named ones.

@jdm jdm added this to To do in web-platform-test failures via automation Dec 3, 2019
@jdm
Copy link
Member

@jdm jdm commented Dec 3, 2019

Relevant to getOwnPropertyDescriptor for legacy objects:

class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod):
def __init__(self, descriptor):
args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'),
Argument('RawHandleId', 'id'),
Argument('RawMutableHandle<PropertyDescriptor>', 'mut desc')]
CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor",
"bool", args)
self.descriptor = descriptor
# https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
def getBody(self):
indexedGetter = self.descriptor.operations['IndexedGetter']
get = "let cx = SafeJSContext::from_ptr(cx);\n"
if indexedGetter:
get += "let index = get_array_index_from_id(*cx, Handle::from_raw(id));\n"
attrs = "JSPROP_ENUMERATE"
if self.descriptor.operations['IndexedSetter'] is None:
attrs += " | JSPROP_READONLY"
# FIXME(#11868) Should assign to desc.value, desc.get() is a copy.
fillDescriptor = ("desc.get().value = result_root.get();\n"
"fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), (%s) as u32);\n"
"return true;" % attrs)
templateValues = {
'jsvalRef': 'result_root.handle_mut()',
'successCode': fillDescriptor,
'pre': 'rooted!(in(*cx) let mut result_root = UndefinedValue());'
}
get += ("if let Some(index) = index {\n" +
" let this = UnwrapProxy(proxy);\n" +
" let this = &*this;\n" +
CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
"}\n")
namedGetter = self.descriptor.operations['NamedGetter']
if namedGetter:
attrs = []
if not self.descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
attrs.append("JSPROP_ENUMERATE")
if self.descriptor.operations['NamedSetter'] is None:
attrs.append("JSPROP_READONLY")
if attrs:
attrs = " | ".join(attrs)
else:
attrs = "0"
# FIXME(#11868) Should assign to desc.value, desc.get() is a copy.
fillDescriptor = ("desc.get().value = result_root.get();\n"
"fill_property_descriptor(MutableHandle::from_raw(desc), proxy.get(), (%s) as u32);\n"
"return true;" % attrs)
templateValues = {
'jsvalRef': 'result_root.handle_mut()',
'successCode': fillDescriptor,
'pre': 'rooted!(in(*cx) let mut result_root = UndefinedValue());'
}
# See the similar-looking in CGDOMJSProxyHandler_get for the spec quote.
condition = "RUST_JSID_IS_STRING(id) || RUST_JSID_IS_INT(id)"
if indexedGetter:
condition = "index.is_none() && (%s)" % condition
# Once we start supporting OverrideBuiltins we need to make
# ResolveOwnProperty or EnumerateOwnProperties filter out named
# properties that shadow prototype properties.
namedGet = """
if %s {
let mut has_on_proto = false;
if !has_property_on_prototype(*cx, proxy_lt, id_lt, &mut has_on_proto) {
return false;
}
if !has_on_proto {
%s
}
}
""" % (condition, CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues), 8).define())
else:
namedGet = ""
return get + """\
rooted!(in(*cx) let mut expando = ptr::null_mut::<JSObject>());
get_expando_object(proxy, expando.handle_mut());
//if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
let proxy_lt = Handle::from_raw(proxy);
let id_lt = Handle::from_raw(id);
if !expando.is_null() {
if !JS_GetPropertyDescriptorById(*cx, expando.handle().into(), id, desc) {
return false;
}
if !desc.obj.is_null() {
// Pretend the property lives on the wrapper.
desc.obj = proxy.get();
return true;
}
}
""" + namedGet + """\
desc.get().obj = ptr::null_mut();
return true;"""
def definition_body(self):
return CGGeneric(self.getBody())

@pshaughn
Copy link
Member Author

@pshaughn pshaughn commented Jan 6, 2020

I don't understand that code very well. In the named getter case, where is it actually looking up the name?

@pshaughn
Copy link
Member Author

@pshaughn pshaughn commented Jan 6, 2020

test(function() {
var form = document.getElementsByTagName("form")[0]
var button = document.getElementsByTagName("input")[0]
assert_equals(button.type, "button")
assert_equals(form.button, button)
var desc = Object.getOwnPropertyDescriptor(form, "button");
assert_equals(desc.value, button);
this test seems to be getting back a descriptor that exists, but that has .value=undefined. Could that be related to the FIXME(#11868) not setting the real value?

@pshaughn pshaughn mentioned this issue Jan 6, 2020
4 of 4 tasks complete
@jdm
Copy link
Member

@jdm jdm commented Jan 6, 2020

That seems entirely plausible, yes.

bors-servo added a commit that referenced this issue Jan 6, 2020
Removing .get() from some property descriptor field assignments to see what happens

This is towards #25036 and #25415; it could have far-reaching implications so I want to test it in isolation and see the results on the full test suite.

A few lines of code had a FIXME(#11868) despite that issue being closed, and looking for the pattern that was marked that way, I found one other unmarked instance of it. It doesn't immediately crash, and maybe it will pass some tests or fail some tests in informative ways.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #___ (GitHub issue number if applicable)

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because ___

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
@pshaughn
Copy link
Member Author

@pshaughn pshaughn commented Jan 6, 2020

Removing the .get() gets us three asserts further down in this particular test (failing on desc.enumerable); if it doesn't break anything else, it's an improvement.

@jdm
Copy link
Member

@jdm jdm commented Jan 6, 2020

What's the enumerable failure? The descriptor returned should be unconditionally enumerable based on the this line.

@pshaughn
Copy link
Member Author

@pshaughn pshaughn commented Jan 6, 2020

The test wants it to not be enumerable:

@jdm
Copy link
Member

@jdm jdm commented Jan 6, 2020

@pshaughn
Copy link
Member Author

@pshaughn pshaughn commented Jan 6, 2020

I see how that happened. The build is set up to fail if that extended attribute's specified without a named getter, and HTMLFormElement didn't have one yet when the extended attribute was being handed out. Window will also need it once it gets a named getter, and HTMLAllCollection once it exists.

@pshaughn pshaughn self-assigned this Jan 6, 2020
@pshaughn
Copy link
Member Author

@pshaughn pshaughn commented Jan 6, 2020

Updated #25446 now that I know it will fix this and not break anything else.

@pshaughn
Copy link
Member Author

@pshaughn pshaughn commented Jan 7, 2020

remaining WebIDL/ecmascript-binding/legacy-platform-object.html failures are HTMLSelectElement-specific and probably just its lack of an indexed setter, #25003

bors-servo added a commit that referenced this issue Jan 10, 2020
Make getOwnPropertyDescriptor hold the correct value for indexed/named properties

This is towards #25036 and #25415; it could have far-reaching implications so I want to test it in isolation and see the results on the full test suite.

A few lines of code had a FIXME(#11868) despite that issue being closed, and looking for the pattern that was marked that way, I found one other unmarked instance of it. It doesn't immediately crash, and maybe it will pass some tests or fail some tests in informative ways.

EDIT: After adding an overlooked extended attribute to HTMLFormElement, this works very well indeed and seems to be worth merging!

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #25036

<!-- Either: -->
- [X] There are tests for these changes OR
- [ ] These changes do not require tests because ___

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
bors-servo added a commit that referenced this issue Jan 10, 2020
Make getOwnPropertyDescriptor hold the correct value for indexed/named properties

This is towards #25036 and #25415; it could have far-reaching implications so I want to test it in isolation and see the results on the full test suite.

A few lines of code had a FIXME(#11868) despite that issue being closed, and looking for the pattern that was marked that way, I found one other unmarked instance of it. It doesn't immediately crash, and maybe it will pass some tests or fail some tests in informative ways.

EDIT: After adding an overlooked extended attribute to HTMLFormElement, this works very well indeed and seems to be worth merging!

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #25036

<!-- Either: -->
- [X] There are tests for these changes OR
- [ ] These changes do not require tests because ___

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
web-platform-test failures automation moved this from To do to Done Jan 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Linked pull requests

Successfully merging a pull request may close this issue.

2 participants
You can’t perform that action at this time.