mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1107953 part 5. Add tests for promise rejections with content-side DOMExceptions, and fix the promise code so those tests actually pass. r=bholley
This commit is contained in:
parent
fdf3bc0a39
commit
6a93d5c443
@ -722,5 +722,32 @@ DOMException::Create(nsresult aRv)
|
|||||||
return inst.forget();
|
return inst.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
DOMException::Sanitize(JSContext* aCx,
|
||||||
|
JS::MutableHandle<JS::Value> aSanitizedValue)
|
||||||
|
{
|
||||||
|
nsRefPtr<DOMException> retval = this;
|
||||||
|
if (mLocation && !mLocation->CallerSubsumes(aCx)) {
|
||||||
|
nsString message;
|
||||||
|
GetMessageMoz(message);
|
||||||
|
nsString name;
|
||||||
|
GetName(name);
|
||||||
|
retval = new dom::DOMException(nsresult(Result()),
|
||||||
|
NS_ConvertUTF16toUTF8(message),
|
||||||
|
NS_ConvertUTF16toUTF8(name),
|
||||||
|
Code());
|
||||||
|
// Now it's possible that the stack on retval still starts with
|
||||||
|
// stuff aCx is not supposed to touch; it depends on what's on the
|
||||||
|
// stack right this second. Walk past all of that.
|
||||||
|
while (retval->mLocation && !retval->mLocation->CallerSubsumes(aCx)) {
|
||||||
|
nsCOMPtr<nsIStackFrame> caller;
|
||||||
|
retval->mLocation->GetCaller(getter_AddRefs(caller));
|
||||||
|
retval->mLocation.swap(caller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToJSValue(aCx, retval, aSanitizedValue);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -156,6 +156,15 @@ public:
|
|||||||
static already_AddRefed<DOMException>
|
static already_AddRefed<DOMException>
|
||||||
Create(nsresult aRv);
|
Create(nsresult aRv);
|
||||||
|
|
||||||
|
// Sanitize() is a workaround for the fact that DOMExceptions can leak stack
|
||||||
|
// information for the first stackframe to callers that should not have access
|
||||||
|
// to it. To prevent this, we check whether aCx subsumes our first stackframe
|
||||||
|
// and if not hand out a JS::Value for a clone of ourselves. Otherwise we
|
||||||
|
// hand out a JS::Value for ourselves.
|
||||||
|
//
|
||||||
|
// If the return value is false, an exception was thrown on aCx.
|
||||||
|
bool Sanitize(JSContext* aCx, JS::MutableHandle<JS::Value> aSanitizedValue);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual ~DOMException() {}
|
virtual ~DOMException() {}
|
||||||
|
@ -234,20 +234,11 @@ ErrorResult::ReportJSExceptionFromJSImplementation(JSContext* aCx)
|
|||||||
nsresult rv =
|
nsresult rv =
|
||||||
UNWRAP_OBJECT(DOMException, &mJSException.toObject(), domException);
|
UNWRAP_OBJECT(DOMException, &mJSException.toObject(), domException);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
// We actually have to create a new DOMException object, because the one we
|
// We may have to create a new DOMException object, because the one we
|
||||||
// have has a stack that includes the chrome code that threw it, and in
|
// have has a stack that includes the chrome code that threw it, and in
|
||||||
// particular has the wrong file/line/column information.
|
// particular has the wrong file/line/column information.
|
||||||
nsString message;
|
|
||||||
domException->GetMessageMoz(message);
|
|
||||||
nsString name;
|
|
||||||
domException->GetName(name);
|
|
||||||
nsRefPtr<dom::DOMException> newException =
|
|
||||||
new dom::DOMException(nsresult(domException->Result()),
|
|
||||||
NS_ConvertUTF16toUTF8(message),
|
|
||||||
NS_ConvertUTF16toUTF8(name),
|
|
||||||
domException->Code());
|
|
||||||
JS::Rooted<JS::Value> reflector(aCx);
|
JS::Rooted<JS::Value> reflector(aCx);
|
||||||
if (!GetOrCreateDOMReflector(aCx, newException, &reflector)) {
|
if (!domException->Sanitize(aCx, &reflector)) {
|
||||||
// Well, that threw _an_ exception. Let's forget ours. We can just
|
// Well, that threw _an_ exception. Let's forget ours. We can just
|
||||||
// unroot and not change the value, since mJSException is completely
|
// unroot and not change the value, since mJSException is completely
|
||||||
// ignored if mResult is not NS_ERROR_DOM_JS_EXCEPTION and we plan to
|
// ignored if mResult is not NS_ERROR_DOM_JS_EXCEPTION and we plan to
|
||||||
@ -301,6 +292,17 @@ ErrorResult::StealJSException(JSContext* cx,
|
|||||||
value.set(mJSException);
|
value.set(mJSException);
|
||||||
js::RemoveRawValueRoot(cx, &mJSException);
|
js::RemoveRawValueRoot(cx, &mJSException);
|
||||||
mResult = NS_OK;
|
mResult = NS_OK;
|
||||||
|
|
||||||
|
if (value.isObject()) {
|
||||||
|
// If it's a DOMException we may need to sanitize it.
|
||||||
|
dom::DOMException* domException;
|
||||||
|
nsresult rv =
|
||||||
|
UNWRAP_OBJECT(DOMException, &value.toObject(), domException);
|
||||||
|
if (NS_SUCCEEDED(rv) && !domException->Sanitize(cx, value)) {
|
||||||
|
JS_GetPendingException(cx, value);
|
||||||
|
JS_ClearPendingException(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -97,7 +97,8 @@ public:
|
|||||||
|
|
||||||
// StealJSException steals the JS Exception from the object. This method must
|
// StealJSException steals the JS Exception from the object. This method must
|
||||||
// be called only if IsJSException() returns true. This method also resets the
|
// be called only if IsJSException() returns true. This method also resets the
|
||||||
// ErrorCode() to NS_OK.
|
// ErrorCode() to NS_OK. The value will be ensured to be sanitized wrt to the
|
||||||
|
// current compartment of cx if it happens to be a DOMException.
|
||||||
void StealJSException(JSContext* cx, JS::MutableHandle<JS::Value> value);
|
void StealJSException(JSContext* cx, JS::MutableHandle<JS::Value> value);
|
||||||
|
|
||||||
void MOZ_ALWAYS_INLINE MightThrowJSException()
|
void MOZ_ALWAYS_INLINE MightThrowJSException()
|
||||||
|
@ -286,6 +286,7 @@ public:
|
|||||||
NS_IMETHOD GetName(nsAString& aFunction) MOZ_OVERRIDE;
|
NS_IMETHOD GetName(nsAString& aFunction) MOZ_OVERRIDE;
|
||||||
NS_IMETHOD GetCaller(nsIStackFrame** aCaller) MOZ_OVERRIDE;
|
NS_IMETHOD GetCaller(nsIStackFrame** aCaller) MOZ_OVERRIDE;
|
||||||
NS_IMETHOD GetFormattedStack(nsAString& aStack) MOZ_OVERRIDE;
|
NS_IMETHOD GetFormattedStack(nsAString& aStack) MOZ_OVERRIDE;
|
||||||
|
virtual bool CallerSubsumes(JSContext* aCx) MOZ_OVERRIDE;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool IsJSFrame() const MOZ_OVERRIDE {
|
virtual bool IsJSFrame() const MOZ_OVERRIDE {
|
||||||
@ -613,6 +614,37 @@ NS_IMETHODIMP StackFrame::ToString(nsACString& _retval)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* virtual */ bool
|
||||||
|
StackFrame::CallerSubsumes(JSContext* aCx)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ bool
|
||||||
|
JSStackFrame::CallerSubsumes(JSContext* aCx)
|
||||||
|
{
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mStack) {
|
||||||
|
// No problem here, there's no data to leak.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIPrincipal* callerPrincipal = nsContentUtils::SubjectPrincipal();
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> unwrappedStack(aCx, js::CheckedUnwrap(mStack));
|
||||||
|
if (!unwrappedStack) {
|
||||||
|
// We can't leak data here either.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIPrincipal* stackPrincipal =
|
||||||
|
nsJSPrincipals::get(js::GetSavedFramePrincipals(unwrappedStack));
|
||||||
|
return callerPrincipal->SubsumesConsideringDomain(stackPrincipal);
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ already_AddRefed<nsIStackFrame>
|
/* static */ already_AddRefed<nsIStackFrame>
|
||||||
JSStackFrame::CreateStack(JSContext* aCx, int32_t aMaxDepth)
|
JSStackFrame::CreateStack(JSContext* aCx, int32_t aMaxDepth)
|
||||||
{
|
{
|
||||||
|
@ -83,6 +83,13 @@ TestInterfaceJS.prototype = {
|
|||||||
return new this._win.Promise(func);
|
return new this._win.Promise(func);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
testPromiseWithDOMExceptionThrowingPromiseInit: function() {
|
||||||
|
return new this._win.Promise(() => {
|
||||||
|
throw new this._win.DOMException("We are a second DOMException",
|
||||||
|
"NotFoundError");
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
testPromiseWithThrowingChromeThenFunction: function() {
|
testPromiseWithThrowingChromeThenFunction: function() {
|
||||||
return this._win.Promise.resolve(5).then(function() {
|
return this._win.Promise.resolve(5).then(function() {
|
||||||
noSuchMethodExistsYo2();
|
noSuchMethodExistsYo2();
|
||||||
@ -93,6 +100,13 @@ TestInterfaceJS.prototype = {
|
|||||||
return this._win.Promise.resolve(10).then(func);
|
return this._win.Promise.resolve(10).then(func);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
testPromiseWithDOMExceptionThrowingThenFunction: function() {
|
||||||
|
return this._win.Promise.resolve(5).then(() => {
|
||||||
|
throw new this._win.DOMException("We are a third DOMException",
|
||||||
|
"NetworkError");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
testPromiseWithThrowingChromeThenable: function() {
|
testPromiseWithThrowingChromeThenable: function() {
|
||||||
// We need to produce a thing that has a "then" property in the page
|
// We need to produce a thing that has a "then" property in the page
|
||||||
// compartment, since we plan to call the page-provided resolve function.
|
// compartment, since we plan to call the page-provided resolve function.
|
||||||
@ -112,6 +126,20 @@ TestInterfaceJS.prototype = {
|
|||||||
// property won't return the function.
|
// property won't return the function.
|
||||||
return this._win.Promise.resolve(Cu.waiveXrays(thenable));
|
return this._win.Promise.resolve(Cu.waiveXrays(thenable));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
testPromiseWithDOMExceptionThrowingThenable: function() {
|
||||||
|
// We need to produce a thing that has a "then" property in the page
|
||||||
|
// compartment, since we plan to call the page-provided resolve function.
|
||||||
|
var thenable = new this._win.Object();
|
||||||
|
Cu.waiveXrays(thenable).then = () => {
|
||||||
|
throw new this._win.DOMException("We are a fourth DOMException",
|
||||||
|
"TypeMismatchError");
|
||||||
|
}
|
||||||
|
return new this._win.Promise(function(resolve) {
|
||||||
|
resolve(thenable)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS])
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS])
|
||||||
|
@ -14,17 +14,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107592
|
|||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
function checkExn(lineNumber, message, filename, testNumber, exn) {
|
function checkExn(lineNumber, name, message, code, filename, testNumber, stack, exn) {
|
||||||
ise(exn.lineNumber, lineNumber,
|
ise(exn.lineNumber, lineNumber,
|
||||||
"Should have the right line number in test " + testNumber);
|
"Should have the right line number in test " + testNumber);
|
||||||
|
ise(exn.name, name,
|
||||||
|
"Should have the right exception name in test " + testNumber);
|
||||||
ise("filename" in exn ? exn.filename : exn.fileName, filename,
|
ise("filename" in exn ? exn.filename : exn.fileName, filename,
|
||||||
"Should have the right file name in test " + testNumber);
|
"Should have the right file name in test " + testNumber);
|
||||||
ise(exn.message, message,
|
ise(exn.message, message,
|
||||||
"Should have the right message in test " + testNumber);
|
"Should have the right message in test " + testNumber);
|
||||||
|
ise(exn.code, code, "Should have the right .code in test " + testNumber);
|
||||||
if (message === "") {
|
if (message === "") {
|
||||||
ise(exn.name, "NS_ERROR_UNEXPECTED",
|
ise(exn.name, "NS_ERROR_UNEXPECTED",
|
||||||
"Should have one of our synthetic exceptions in test " + testNumber);
|
"Should have one of our synthetic exceptions in test " + testNumber);
|
||||||
}
|
}
|
||||||
|
ise(exn.stack, stack, "Should have the right stack in test " + testNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensurePromiseFail(testNumber, value) {
|
function ensurePromiseFail(testNumber, value) {
|
||||||
@ -39,34 +43,55 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107592
|
|||||||
Promise.all([
|
Promise.all([
|
||||||
t.testPromiseWithThrowingChromePromiseInit().then(
|
t.testPromiseWithThrowingChromePromiseInit().then(
|
||||||
ensurePromiseFail.bind(null, 1),
|
ensurePromiseFail.bind(null, 1),
|
||||||
checkExn.bind(null, 40, "", ourFile, 1)),
|
checkExn.bind(null, 44, "NS_ERROR_UNEXPECTED", "", undefined,
|
||||||
|
ourFile, 1,
|
||||||
|
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_promise_rejections_from_jsimplemented.html:44:6\n")),
|
||||||
t.testPromiseWithThrowingContentPromiseInit(function() {
|
t.testPromiseWithThrowingContentPromiseInit(function() {
|
||||||
thereIsNoSuchContentFunction1();
|
thereIsNoSuchContentFunction1();
|
||||||
}).then(
|
}).then(
|
||||||
ensurePromiseFail.bind(null, 2),
|
ensurePromiseFail.bind(null, 2),
|
||||||
checkExn.bind(null, 44,
|
checkExn.bind(null, 50, "ReferenceError",
|
||||||
"thereIsNoSuchContentFunction1 is not defined",
|
"thereIsNoSuchContentFunction1 is not defined",
|
||||||
ourFile, 2)),
|
undefined, ourFile, 2,
|
||||||
|
"doTest/<@http://mochi.test:8888/tests/dom/bindings/test/test_promise_rejections_from_jsimplemented.html:50:11\ndoTest@http://mochi.test:8888/tests/dom/bindings/test/test_promise_rejections_from_jsimplemented.html:49:7\n")),
|
||||||
t.testPromiseWithThrowingChromeThenFunction().then(
|
t.testPromiseWithThrowingChromeThenFunction().then(
|
||||||
ensurePromiseFail.bind(null, 3),
|
ensurePromiseFail.bind(null, 3),
|
||||||
checkExn.bind(null, 0, "", "", 3)),
|
checkExn.bind(null, 0, "NS_ERROR_UNEXPECTED", "", undefined, "", 3, "")),
|
||||||
t.testPromiseWithThrowingContentThenFunction(function() {
|
t.testPromiseWithThrowingContentThenFunction(function() {
|
||||||
thereIsNoSuchContentFunction2();
|
thereIsNoSuchContentFunction2();
|
||||||
}).then(
|
}).then(
|
||||||
ensurePromiseFail.bind(null, 4),
|
ensurePromiseFail.bind(null, 4),
|
||||||
checkExn.bind(null, 54,
|
checkExn.bind(null, 61, "ReferenceError",
|
||||||
"thereIsNoSuchContentFunction2 is not defined",
|
"thereIsNoSuchContentFunction2 is not defined",
|
||||||
ourFile, 4)),
|
undefined, ourFile, 4,
|
||||||
|
"doTest/<@http://mochi.test:8888/tests/dom/bindings/test/test_promise_rejections_from_jsimplemented.html:61:11\n")),
|
||||||
t.testPromiseWithThrowingChromeThenable().then(
|
t.testPromiseWithThrowingChromeThenable().then(
|
||||||
ensurePromiseFail.bind(null, 5),
|
ensurePromiseFail.bind(null, 5),
|
||||||
checkExn.bind(null, 0, "", "", 5)),
|
checkExn.bind(null, 0, "NS_ERROR_UNEXPECTED", "", undefined, "", 5, "")),
|
||||||
t.testPromiseWithThrowingContentThenable({
|
t.testPromiseWithThrowingContentThenable({
|
||||||
then: function() { thereIsNoSuchContentFunction3(); }
|
then: function() { thereIsNoSuchContentFunction3(); }
|
||||||
}).then(
|
}).then(
|
||||||
ensurePromiseFail.bind(null, 6),
|
ensurePromiseFail.bind(null, 6),
|
||||||
checkExn.bind(null, 64,
|
checkExn.bind(null, 72, "ReferenceError",
|
||||||
"thereIsNoSuchContentFunction3 is not defined",
|
"thereIsNoSuchContentFunction3 is not defined",
|
||||||
ourFile, 6)),
|
undefined, ourFile, 6,
|
||||||
|
"doTest/<.then@http://mochi.test:8888/tests/dom/bindings/test/test_promise_rejections_from_jsimplemented.html:72:32\n")),
|
||||||
|
t.testPromiseWithDOMExceptionThrowingPromiseInit().then(
|
||||||
|
ensurePromiseFail.bind(null, 7),
|
||||||
|
checkExn.bind(null, 79, "NotFoundError",
|
||||||
|
"We are a second DOMException",
|
||||||
|
DOMException.NOT_FOUND_ERR, ourFile, 7,
|
||||||
|
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_promise_rejections_from_jsimplemented.html:79:6\n")),
|
||||||
|
t.testPromiseWithDOMExceptionThrowingThenFunction().then(
|
||||||
|
ensurePromiseFail.bind(null, 8),
|
||||||
|
checkExn.bind(null, 0, "NetworkError",
|
||||||
|
"We are a third DOMException",
|
||||||
|
DOMException.NETWORK_ERR, "", 8, "")),
|
||||||
|
t.testPromiseWithDOMExceptionThrowingThenable().then(
|
||||||
|
ensurePromiseFail.bind(null, 9),
|
||||||
|
checkExn.bind(null, 0, "TypeMismatchError",
|
||||||
|
"We are a fourth DOMException",
|
||||||
|
DOMException.TYPE_MISMATCH_ERR, "", 9, "")),
|
||||||
]).then(SimpleTest.finish,
|
]).then(SimpleTest.finish,
|
||||||
function() {
|
function() {
|
||||||
ok(false, "One of our catch statements totally failed");
|
ok(false, "One of our catch statements totally failed");
|
||||||
|
@ -212,6 +212,11 @@ protected:
|
|||||||
if (rv.Failed()) {
|
if (rv.Failed()) {
|
||||||
JS::Rooted<JS::Value> exn(cx);
|
JS::Rooted<JS::Value> exn(cx);
|
||||||
if (rv.IsJSException()) {
|
if (rv.IsJSException()) {
|
||||||
|
// Enter the compartment of mPromise before stealing the JS exception,
|
||||||
|
// since the StealJSException call will use the current compartment for
|
||||||
|
// a security check that determines how much of the stack we're allowed
|
||||||
|
// to see and we'll be exposing that stack to consumers of mPromise.
|
||||||
|
JSAutoCompartment ac(cx, mPromise->GlobalJSObject());
|
||||||
rv.StealJSException(cx, &exn);
|
rv.StealJSException(cx, &exn);
|
||||||
} else {
|
} else {
|
||||||
// Convert the ErrorResult to a JS exception object that we can reject
|
// Convert the ErrorResult to a JS exception object that we can reject
|
||||||
@ -579,7 +584,14 @@ Promise::CallInitFunction(const GlobalObject& aGlobal,
|
|||||||
|
|
||||||
if (aRv.IsJSException()) {
|
if (aRv.IsJSException()) {
|
||||||
JS::Rooted<JS::Value> value(cx);
|
JS::Rooted<JS::Value> value(cx);
|
||||||
aRv.StealJSException(cx, &value);
|
{ // scope for ac
|
||||||
|
// Enter the compartment of our global before stealing the JS exception,
|
||||||
|
// since the StealJSException call will use the current compartment for
|
||||||
|
// a security check that determines how much of the stack we're allowed
|
||||||
|
// to see, and we'll be exposing that stack to consumers of this promise.
|
||||||
|
JSAutoCompartment ac(cx, GlobalJSObject());
|
||||||
|
aRv.StealJSException(cx, &value);
|
||||||
|
}
|
||||||
|
|
||||||
// we want the same behavior as this JS implementation:
|
// we want the same behavior as this JS implementation:
|
||||||
// function Promise(arg) { try { arg(a, b); } catch (e) { this.reject(e); }}
|
// function Promise(arg) { try { arg(a, b); } catch (e) { this.reject(e); }}
|
||||||
|
@ -214,7 +214,15 @@ WrapperPromiseCallback::Call(JSContext* aCx,
|
|||||||
if (rv.Failed()) {
|
if (rv.Failed()) {
|
||||||
JS::Rooted<JS::Value> value(aCx);
|
JS::Rooted<JS::Value> value(aCx);
|
||||||
if (rv.IsJSException()) {
|
if (rv.IsJSException()) {
|
||||||
rv.StealJSException(aCx, &value);
|
{ // scope for ac
|
||||||
|
// Enter the compartment of mNextPromise before stealing the JS
|
||||||
|
// exception, since the StealJSException call will use the current
|
||||||
|
// compartment for a security check that determines how much of the
|
||||||
|
// stack we're allowed to see and we'll be exposing that stack to
|
||||||
|
// consumers of mPromise.
|
||||||
|
JSAutoCompartment ac(aCx, mNextPromise->GlobalJSObject());
|
||||||
|
rv.StealJSException(aCx, &value);
|
||||||
|
}
|
||||||
|
|
||||||
if (!JS_WrapValue(aCx, &value)) {
|
if (!JS_WrapValue(aCx, &value)) {
|
||||||
NS_WARNING("Failed to wrap value into the right compartment.");
|
NS_WARNING("Failed to wrap value into the right compartment.");
|
||||||
|
@ -59,8 +59,11 @@ interface TestInterfaceJS {
|
|||||||
// Tests for promise-rejection behavior
|
// Tests for promise-rejection behavior
|
||||||
Promise<void> testPromiseWithThrowingChromePromiseInit();
|
Promise<void> testPromiseWithThrowingChromePromiseInit();
|
||||||
Promise<void> testPromiseWithThrowingContentPromiseInit(PromiseInit func);
|
Promise<void> testPromiseWithThrowingContentPromiseInit(PromiseInit func);
|
||||||
|
Promise<void> testPromiseWithDOMExceptionThrowingPromiseInit();
|
||||||
Promise<void> testPromiseWithThrowingChromeThenFunction();
|
Promise<void> testPromiseWithThrowingChromeThenFunction();
|
||||||
Promise<void> testPromiseWithThrowingContentThenFunction(AnyCallback func);
|
Promise<void> testPromiseWithThrowingContentThenFunction(AnyCallback func);
|
||||||
|
Promise<void> testPromiseWithDOMExceptionThrowingThenFunction();
|
||||||
Promise<void> testPromiseWithThrowingChromeThenable();
|
Promise<void> testPromiseWithThrowingChromeThenable();
|
||||||
Promise<void> testPromiseWithThrowingContentThenable(object thenable);
|
Promise<void> testPromiseWithThrowingContentThenable(object thenable);
|
||||||
|
Promise<void> testPromiseWithDOMExceptionThrowingThenable();
|
||||||
};
|
};
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
|
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
[scriptable, uuid(f80ac10b-68dd-4482-a8c2-3cbe13fa89af)]
|
[ptr] native JSContext(JSContext);
|
||||||
|
|
||||||
|
[scriptable, uuid(4f2927e5-ae85-4c6b-93d2-2f639af6a236)]
|
||||||
interface nsIStackFrame : nsISupports
|
interface nsIStackFrame : nsISupports
|
||||||
{
|
{
|
||||||
// see nsIProgrammingLanguage for list of language consts
|
// see nsIProgrammingLanguage for list of language consts
|
||||||
@ -30,6 +32,10 @@ interface nsIStackFrame : nsISupports
|
|||||||
readonly attribute AString formattedStack;
|
readonly attribute AString formattedStack;
|
||||||
|
|
||||||
AUTF8String toString();
|
AUTF8String toString();
|
||||||
|
|
||||||
|
// Return whether this stack frame can be accessed by the caller. This is
|
||||||
|
// safe to call on non-main threads, but will always report "yes" there.
|
||||||
|
[noscript, notxpcom, nostdcall] boolean callerSubsumes(in JSContext aCx);
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, uuid(1caf1461-be1d-4b79-a552-5292b6bf3c35)]
|
[scriptable, uuid(1caf1461-be1d-4b79-a552-5292b6bf3c35)]
|
||||||
|
Loading…
Reference in New Issue
Block a user