Bug 1173593. Make it possible to throw TypeError (or, in fact, any other Error from the content compartment) from js-implemented webidl. r=bholley

This commit is contained in:
Boris Zbarsky 2015-06-15 20:09:36 -04:00
parent ba58ba4578
commit 0d146ab622
5 changed files with 115 additions and 34 deletions

View File

@ -34,8 +34,6 @@
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/DOMErrorBinding.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/DOMExceptionBinding.h"
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/HTMLObjectElement.h"
#include "mozilla/dom/HTMLObjectElementBinding.h"
@ -284,26 +282,16 @@ ErrorResult::ReportJSExceptionFromJSImplementation(JSContext* aCx)
MOZ_ASSERT(!mMightHaveUnreportedJSException,
"Why didn't you tell us you planned to handle JS exceptions?");
dom::DOMException* domException;
nsresult rv =
UNWRAP_OBJECT(DOMException, &mJSException.toObject(), domException);
if (NS_SUCCEEDED(rv)) {
// Check for a DOMError, since we convert that into an Error in the content
// compartment. We can probably remove that now; see bug 1174954.
dom::DOMError* domError;
nsresult rv = UNWRAP_OBJECT(DOMError, &mJSException.toObject(), domError);
if (NS_FAILED(rv)) {
// Just report it.
ReportJSException(aCx);
return;
}
dom::DOMError* domError;
rv = UNWRAP_OBJECT(DOMError, &mJSException.toObject(), domError);
if (NS_FAILED(rv)) {
// Unwrapping really shouldn't fail here: if mExceptionHandling is set to
// eRethrowContentExceptions then the CallSetup destructor only stores an
// exception if it unwraps to DOMError or DOMException. If we reach this
// then either mExceptionHandling wasn't set to eRethrowContentExceptions
// and we shouldn't be calling ReportJSExceptionFromJSImplementation or
// something went really wrong.
NS_RUNTIMEABORT("We stored a non-DOMError exception!");
}
nsString message;
domError->GetMessage(message);

View File

@ -6,10 +6,6 @@
#include "mozilla/dom/CallbackObject.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/DOMErrorBinding.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/DOMExceptionBinding.h"
#include "jsfriendapi.h"
#include "nsIScriptGlobalObject.h"
#include "nsIXPConnect.h"
@ -224,8 +220,7 @@ CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aExcepti
MOZ_ASSERT(mCompartment);
// Now we only want to throw an exception to the caller if the object that was
// thrown is a DOMError or DOMException object in the caller compartment
// (which we stored in mCompartment).
// thrown is in the caller compartment (which we stored in mCompartment).
if (!aException.isObject()) {
return false;
@ -233,14 +228,7 @@ CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aExcepti
JS::Rooted<JSObject*> obj(mCx, &aException.toObject());
obj = js::UncheckedUnwrap(obj, /* stopAtOuter = */ false);
if (js::GetObjectCompartment(obj) != mCompartment) {
return false;
}
DOMError* domError;
DOMException* domException;
return NS_SUCCEEDED(UNWRAP_OBJECT(DOMError, obj, domError)) ||
NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException));
return js::GetObjectCompartment(obj) == mCompartment;
}
CallbackObject::CallSetup::~CallSetup()

View File

@ -73,6 +73,22 @@ TestInterfaceJS.prototype = {
"NotSupportedError");
},
testThrowTypeError: function() {
throw new this._win.TypeError("We are a TypeError");
},
testThrowCallbackError: function(callback) {
callback();
},
testThrowXraySelfHosted: function() {
this._win.Array.indexOf();
},
testThrowSelfHosted: function() {
Array.indexOf();
},
testPromiseWithThrowingChromePromiseInit: function() {
return new this._win.Promise(function() {
noSuchMethodExistsYo1();

View File

@ -51,9 +51,86 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107592
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
"Should still have the right file name");
is(e.lineNumber, 38, "Should still have the right line number");
todo_is(e.columnNumber, 7,
"No column number support for DOMException yet");
todo_isnot(e.columnNumber, 0,
"No column number support for DOMException yet");
}
try {
t.testThrowTypeError();
} catch (e) {
ok(e instanceof TypeError, "Should have a TypeError here");
ok(!(e instanceof DOMException), "Should not have DOMException here (2)");
ok(!("code" in e), "Should not have a 'code' property (2)");
is(e.name, "TypeError", "Should be named TypeError");
is(e.message, "We are a TypeError",
"Should also have the right message (2)");
is(e.stack,
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:59:7\n",
"Exception stack for TypeError should only show our code");
is(e.fileName,
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
"Should still have the right file name for TypeError");
is(e.lineNumber, 59, "Should still have the right line number for TypeError");
is(e.columnNumber, 7, "Should have the right column number for TypeError");
}
try {
t.testThrowCallbackError(function() { Array.indexOf() });
} catch (e) {
ok(e instanceof TypeError, "Should have a TypeError here (3)");
ok(!(e instanceof DOMException), "Should not have DOMException here (3)");
ok(!("code" in e), "Should not have a 'code' property (3)");
is(e.name, "TypeError", "Should be named TypeError (3)");
is(e.message, "missing argument 0 when calling function Array.indexOf",
"Should also have the right message (3)");
is(e.stack,
"doTest/<@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:78:45\n" +
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:78:7\n"
,
"Exception stack for TypeError should only show our code (3)");
is(e.fileName,
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
"Should still have the right file name for TypeError (3)");
is(e.lineNumber, 78, "Should still have the right line number for TypeError (3)");
is(e.columnNumber, 45, "Should have the right column number for TypeError (3)");
}
try {
t.testThrowXraySelfHosted();
} catch (e) {
ok(!(e instanceof Error), "Should have an Exception here (4)");
ok(!(e instanceof DOMException), "Should not have DOMException here (4)");
ok(!("code" in e), "Should not have a 'code' property (4)");
is(e.name, "NS_ERROR_UNEXPECTED", "Name should be sanitized (4)");
is(e.message, "", "Message should be sanitized (5)");
is(e.stack,
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:99:7\n",
"Exception stack for sanitized exception should only show our code (4)");
is(e.filename,
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
"Should still have the right file name for sanitized exception (4)");
is(e.lineNumber, 99, "Should still have the right line number for sanitized exception (4)");
todo_isnot(e.columnNumber, 0, "Should have the right column number for sanitized exception (4)");
}
try {
t.testThrowSelfHosted();
} catch (e) {
ok(!(e instanceof Error), "Should have an Exception here (5)");
ok(!(e instanceof DOMException), "Should not have DOMException here (5)");
ok(!("code" in e), "Should not have a 'code' property (5)");
is(e.name, "NS_ERROR_UNEXPECTED", "Name should be sanitized (5)");
is(e.message, "", "Message should be sanitized (5)");
is(e.stack,
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:117:7\n",
"Exception stack for sanitized exception should only show our code (5)");
is(e.filename,
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
"Should still have the right file name for sanitized exception (5)");
is(e.lineNumber, 117, "Should still have the right line number for sanitized exception (5)");
todo_isnot(e.columnNumber, 0, "Should have the right column number for sanitized exception (5)");
}
SimpleTest.finish();
}

View File

@ -56,6 +56,18 @@ interface TestInterfaceJS {
[Throws]
void testThrowDOMException();
[Throws]
void testThrowTypeError();
[Throws]
void testThrowCallbackError(Function callback);
[Throws]
void testThrowXraySelfHosted();
[Throws]
void testThrowSelfHosted();
// Tests for promise-rejection behavior
Promise<void> testPromiseWithThrowingChromePromiseInit();
Promise<void> testPromiseWithThrowingContentPromiseInit(PromiseInit func);