diff --git a/dom/bindings/CallbackObject.cpp b/dom/bindings/CallbackObject.cpp index 2b6af53a175c..7c7d2c6b4c97 100644 --- a/dom/bindings/CallbackObject.cpp +++ b/dom/bindings/CallbackObject.cpp @@ -273,9 +273,11 @@ CallbackObject::CallSetup::~CallSetup() // runs. Note that we've already run ~mAc, effectively, so we don't have // to worry about ordering here. if (mErrorResult.IsJSContextException()) { - // XXXkhuey bug 1117269. - // This won't be true anymore because we will report the exception on - // the JSContext ... so throw something else. + // XXXkhuey bug 1117269. When this is fixed, please consider fixing + // ThrowExceptionValueIfSafe over in Exceptions.cpp in the same way. + + // IsJSContextException shouldn't be true anymore because we will report + // the exception on the JSContext ... so throw something else. mErrorResult.Throw(NS_ERROR_UNEXPECTED); } } diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp index 4584d8323722..a9518cc36d23 100644 --- a/dom/bindings/Exceptions.cpp +++ b/dom/bindings/Exceptions.cpp @@ -25,6 +25,50 @@ namespace mozilla { namespace dom { +// Throw the given exception value if it's safe. If it's not safe, then +// synthesize and throw a new exception value for NS_ERROR_UNEXPECTED. The +// incoming value must be in the compartment of aCx. This function guarantees +// that an exception is pending on aCx when it returns. +static void +ThrowExceptionValueIfSafe(JSContext* aCx, JS::Handle exnVal, + nsIException* aOriginalException) +{ + MOZ_ASSERT(aOriginalException); + + if (!exnVal.isObject()) { + JS_SetPendingException(aCx, exnVal); + return; + } + + JS::Rooted exnObj(aCx, &exnVal.toObject()); + MOZ_ASSERT(js::IsObjectInContextCompartment(exnObj, aCx), + "exnObj needs to be in the right compartment for the " + "CheckedUnwrap thing to make sense"); + + if (js::CheckedUnwrap(exnObj)) { + // This is an object we're allowed to work with, so just go ahead and throw + // it. + JS_SetPendingException(aCx, exnVal); + return; + } + + // We could probably Throw(aCx, NS_ERROR_UNEXPECTED) here, and it would do the + // right thing due to there not being an existing exception on the runtime at + // this point, but it's clearer to explicitly do the thing we want done. This + // is also why we don't just call ThrowExceptionObject on the Exception we + // create: it would do the right thing, but that fact is not obvious. + RefPtr syntheticException = + CreateException(aCx, NS_ERROR_UNEXPECTED); + JS::Rooted syntheticVal(aCx); + if (!GetOrCreateDOMReflector(aCx, syntheticException, &syntheticVal)) { + return; + } + MOZ_ASSERT(syntheticVal.isObject() && + !js::IsWrapper(&syntheticVal.toObject()), + "Must have a reflector here, not a wrapper"); + JS_SetPendingException(aCx, syntheticVal); +} + void ThrowExceptionObject(JSContext* aCx, nsIException* aException) { @@ -44,7 +88,7 @@ ThrowExceptionObject(JSContext* aCx, nsIException* aException) return; } - JS_SetPendingException(aCx, val); + ThrowExceptionValueIfSafe(aCx, val, aException); } void @@ -76,7 +120,7 @@ ThrowExceptionObject(JSContext* aCx, Exception* aException) if (!JS_WrapValue(aCx, &thrown)) { return; } - JS_SetPendingException(aCx, thrown); + ThrowExceptionValueIfSafe(aCx, thrown, aException); return; } @@ -84,7 +128,7 @@ ThrowExceptionObject(JSContext* aCx, Exception* aException) return; } - JS_SetPendingException(aCx, thrown); + ThrowExceptionValueIfSafe(aCx, thrown, aException); } bool