Bug 1043690 part 2. Change the codegen for DOM proxies to ignore named props when looking up property descriptors on [[Set]]. r=efaust

This commit is contained in:
Boris Zbarsky 2014-08-01 23:37:14 -04:00
parent 6bc778bcca
commit b1c1e22da4
7 changed files with 104 additions and 13 deletions

View File

@ -83,11 +83,12 @@ GetWindowFromGlobal(JSObject* aGlobal)
}
bool
WindowNamedPropertiesHandler::getOwnPropertyDescriptor(JSContext* aCx,
JS::Handle<JSObject*> aProxy,
JS::Handle<jsid> aId,
JS::MutableHandle<JSPropertyDescriptor> aDesc)
const
WindowNamedPropertiesHandler::getOwnPropDescriptor(JSContext* aCx,
JS::Handle<JSObject*> aProxy,
JS::Handle<jsid> aId,
bool /* unused */,
JS::MutableHandle<JSPropertyDescriptor> aDesc)
const
{
if (!JSID_IS_STRING(aId)) {
// Nothing to do if we're resolving a non-string property.

View File

@ -28,10 +28,11 @@ public:
return false;
}
virtual bool
getOwnPropertyDescriptor(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::Handle<jsid> aId,
JS::MutableHandle<JSPropertyDescriptor> aDesc)
const MOZ_OVERRIDE;
getOwnPropDescriptor(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::Handle<jsid> aId,
bool /* unused */,
JS::MutableHandle<JSPropertyDescriptor> aDesc)
const MOZ_OVERRIDE;
virtual bool
defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy,
JS::Handle<jsid> aId,

View File

@ -9637,13 +9637,14 @@ class CGProxyUnwrap(CGAbstractMethod):
type=self.descriptor.nativeType)
class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod):
def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'proxy'),
Argument('JS::Handle<jsid>', 'id'),
Argument('bool', 'ignoreNamedProps'),
Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc')]
ClassMethod.__init__(self, "getOwnPropertyDescriptor", "bool", args,
ClassMethod.__init__(self, "getOwnPropDescriptor", "bool", args,
virtual=True, override=True, const=True)
self.descriptor = descriptor
@ -9714,6 +9715,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
condition = "!HasPropertyOnPrototype(cx, proxy, id)"
if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
condition = "(!isXray || %s)" % condition
condition = "!ignoreNamedProps && " + condition
if self.descriptor.supportsIndexedProperties():
condition = "!IsArrayIndex(index) && " + condition
namedGet = (CGIfWrapper(CGProxyNamedGetter(self.descriptor, templateValues),
@ -10372,7 +10374,7 @@ class CGDOMJSProxyHandler(CGClass):
def __init__(self, descriptor):
assert (descriptor.supportsIndexedProperties() or
descriptor.supportsNamedProperties())
methods = [CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor),
methods = [CGDOMJSProxyHandler_getOwnPropDescriptor(descriptor),
CGDOMJSProxyHandler_defineProperty(descriptor),
ClassUsingDeclaration("mozilla::dom::DOMProxyHandler",
"defineProperty"),

View File

@ -183,6 +183,16 @@ BaseDOMProxyHandler::getPropertyDescriptor(JSContext* cx,
return JS_GetPropertyDescriptorById(cx, proto, id, desc);
}
bool
BaseDOMProxyHandler::getOwnPropertyDescriptor(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,
MutableHandle<JSPropertyDescriptor> desc) const
{
return getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ false,
desc);
}
bool
DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
MutableHandle<JSPropertyDescriptor> desc, bool* defined) const
@ -221,7 +231,30 @@ DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<JSObject*> r
if (done) {
return true;
}
return mozilla::dom::BaseDOMProxyHandler::set(cx, proxy, receiver, id, strict, vp);
// Make sure to ignore our named properties when checking for own
// property descriptors for a set.
JS::Rooted<JSPropertyDescriptor> desc(cx);
if (!getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ true,
&desc)) {
return false;
}
bool descIsOwn = desc.object() != nullptr;
if (!desc.object()) {
// Don't just use getPropertyDescriptor, unlike BaseProxyHandler::set,
// because that would call getOwnPropertyDescriptor on ourselves. Instead,
// directly delegate to the proto, if any.
JS::Rooted<JSObject*> proto(cx);
if (!js::GetObjectProto(cx, proxy, &proto)) {
return false;
}
if (proto && !JS_GetPropertyDescriptorById(cx, proto, id, &desc)) {
return false;
}
}
return js::SetPropertyIgnoringNamedGetter(cx, this, proxy, receiver, id,
&desc, descIsOwn, strict, vp);
}
bool

View File

@ -49,6 +49,9 @@ public:
bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::Handle<JSObject*> callable) const MOZ_OVERRIDE;
@ -70,6 +73,16 @@ protected:
virtual bool ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy,
unsigned flags,
JS::AutoIdVector& props) const = 0;
// Hook for subclasses to allow set() to ignore named props while other things
// that look at property descriptors see them. This is intentionally not
// named getOwnPropertyDescriptor to avoid subclasses that override it hiding
// our public getOwnPropertyDescriptor.
virtual bool getOwnPropDescriptor(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,
bool ignoreNamedProps,
JS::MutableHandle<JSPropertyDescriptor> desc) const = 0;
};
class DOMProxyHandler : public BaseDOMProxyHandler

View File

@ -43,6 +43,7 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure; bug 926547
[test_scalarvaluestring.html]
skip-if = debug == false
[test_sequence_wrapping.html]
[test_setWithNamedGetterNoNamedSetter.html]
[test_throwing_method_noDCE.html]
[test_treat_non_object_as_null.html]
[test_traceProtos.html]

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1043690
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1043690</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1043690">Mozilla Bug 1043690</a>
<p id="display"></p>
<div id="content" style="display: none">
<form>
<input name="action">
</form>
</div>
<script type="application/javascript">
/** Test for Bug 1043690 **/
var f = document.querySelector("form");
var i = document.querySelector("input");
ise(f.getAttribute("action"), null, "Should have no action attribute");
ise(f.action, i, "form.action should be the input");
f.action = "http://example.org";
ise(f.getAttribute("action"), "http://example.org",
"Should have an action attribute now");
ise(f.action, i, "form.action should still be the input");
i.remove();
ise(f.action, "http://example.org/",
"form.action should no longer be shadowed");
</script>
<pre id="test">
</pre>
</body>
</html>