Bug 1359859. Use the right entry global for XBL constructor/destructor/field execution. r=bholley

The test doesn't verify that the exceptions are reported to the browser console,
but I manually checked that they are.  Adding a test for that part could be
pretty annoying.
This commit is contained in:
Boris Zbarsky 2017-04-26 13:57:55 -04:00
parent 708a1b1c64
commit 77a2c8f1f2
5 changed files with 72 additions and 14 deletions

View File

@ -403,11 +403,15 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
// We are going to run script via EvaluateString, so we need a script entry
// point, but as this is XBL related it does not appear in the HTML spec.
AutoEntryScript aes(globalObject, "XBL <field> initialization", true);
JSContext* cx = aes.cx();
NS_ASSERTION(!::JS_IsExceptionPending(cx),
"Shouldn't get here when an exception is pending!");
// We need an actual JSContext to do GetScopeForXBLExecution, and it needs to
// be in the compartment of globalObject. But we want our XBL execution scope
// to be our entry global.
AutoJSAPI jsapi;
if (!jsapi.Init(globalObject)) {
return NS_ERROR_UNEXPECTED;
}
MOZ_ASSERT(!::JS_IsExceptionPending(jsapi.cx()),
"Shouldn't get here when an exception is pending!");
JSAddonId* addonId = MapURIToAddonID(aBindingDocURI);
@ -419,9 +423,12 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
// First, enter the xbl scope, build the element's scope chain, and use
// that as the scope chain for the evaluation.
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, aBoundNode, addonId));
JS::Rooted<JSObject*> scopeObject(jsapi.cx(),
xpc::GetScopeForXBLExecution(jsapi.cx(), aBoundNode, addonId));
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
JSAutoCompartment ac(cx, scopeObject);
AutoEntryScript aes(scopeObject, "XBL <field> initialization", true);
JSContext* cx = aes.cx();
JS::Rooted<JS::Value> result(cx);
JS::CompileOptions options(cx);
@ -446,7 +453,8 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW) {
// Report the exception now, before we try using the JSContext for
// the JS_DefineUCProperty call.
// the JS_DefineUCProperty call. Note that this reports in our current
// compartment, which is the XBL scope.
aes.ReportException();
}

View File

@ -285,15 +285,24 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement, JSAddonId* aAd
// We are going to run script via JS::Call, so we need a script entry point,
// but as this is XBL related it does not appear in the HTML spec.
dom::AutoEntryScript aes(global, "XBL <constructor>/<destructor> invocation");
JSContext* cx = aes.cx();
// We need an actual JSContext to do GetScopeForXBLExecution, and it needs to
// be in the compartment of globalObject. But we want our XBL execution scope
// to be our entry global.
AutoJSAPI jsapi;
if (!jsapi.Init(global)) {
return NS_ERROR_UNEXPECTED;
}
JS::Rooted<JSObject*> globalObject(cx, global->GetGlobalJSObject());
JS::Rooted<JSObject*> globalObject(jsapi.cx(), global->GetGlobalJSObject());
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, aAddonId));
JS::Rooted<JSObject*> scopeObject(jsapi.cx(),
xpc::GetScopeForXBLExecution(jsapi.cx(), globalObject, aAddonId));
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
JSAutoCompartment ac(cx, scopeObject);
dom::AutoEntryScript aes(scopeObject,
"XBL <constructor>/<destructor> invocation",
true);
JSContext* cx = aes.cx();
JS::AutoObjectVector scopeChain(cx);
if (!nsJSUtils::GetScopeChainForElement(cx, aBoundElement->AsElement(),
scopeChain)) {

View File

@ -39,3 +39,4 @@ support-files =
[test_bug872273.xhtml]
[test_bug1086996.xhtml]
[test_bug1098628_throw_from_construct.xhtml]
[test_bug1359859.xhtml]

View File

@ -11,7 +11,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1098628
/** Test for Bug 1098628 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.expectUncaughtException();
SimpleTest.monitorConsole(SimpleTest.finish, [{errorMessage: new RegExp('flimfniffle')}]);
addLoadEvent(function() {
SimpleTest.executeSoon(SimpleTest.endMonitorConsole);

View File

@ -0,0 +1,41 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1359859
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="testBinding">
<implementation>
<constructor>
XPCNativeWrapper.unwrap(window).running();
this.constructed = true;
throw new Error("Constructor threw");
</constructor>
<field name="throwingField">throw new Error("field threw")</field>
<field name="normalField">"hello"</field>
</implementation>
</binding>
</bindings>
<script>
// We need to wait for the binding to load.
SimpleTest.waitForExplicitFinish();
function running() {
// Wait for the rest of the constructor to run
SimpleTest.executeSoon(function() {
is(document.getElementById("bound").throwingField, undefined,
"Should not have a value for a throwing field");
is(document.getElementById("bound").normalField, "hello",
"Binding should be installed");
// The real test is that we haven't gotten any error events so far.
SimpleTest.finish();
});
}
</script>
</head>
<body>
<div id="bound" style="-moz-binding: url(#testBinding)"/>
</body>
</html>