window.onerror catches JSON.parse error in Promise fulfillment

This commit is contained in:
janekptacijarabaci
2017-05-06 00:29:57 +02:00
committed by roytam1
parent 500bbf02e9
commit 671b416855
22 changed files with 168 additions and 189 deletions
+2 -43
View File
@@ -173,7 +173,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(Exception)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -184,7 +183,6 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInner)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
tmp->mThrownJSVal.setNull();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -244,7 +242,7 @@ Exception::Exception(const nsACString& aMessage,
}
}
Initialize(aMessage, aResult, aName, location, aData, nullptr);
Initialize(aMessage, aResult, aName, location, aData);
}
Exception::Exception()
@@ -403,18 +401,6 @@ Exception::GetData(nsISupports** aData)
return NS_OK;
}
/* readonly attribute nsIException inner; */
NS_IMETHODIMP
Exception::GetInner(nsIException** aException)
{
NS_ENSURE_ARG_POINTER(aException);
NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsIException> inner = mInner;
inner.forget(aException);
return NS_OK;
}
/* AUTF8String toString (); */
NS_IMETHODIMP
Exception::ToString(nsACString& _retval)
@@ -463,7 +449,7 @@ Exception::ToString(nsACString& _retval)
NS_IMETHODIMP
Exception::Initialize(const nsACString& aMessage, nsresult aResult,
const nsACString& aName, nsIStackFrame *aLocation,
nsISupports *aData, nsIException *aInner)
nsISupports *aData)
{
NS_ENSURE_FALSE(mInitialized, NS_ERROR_ALREADY_INITIALIZED);
@@ -483,7 +469,6 @@ Exception::Initialize(const nsACString& aMessage, nsresult aResult,
}
mData = aData;
mInner = aInner;
mInitialized = true;
return NS_OK;
@@ -552,13 +537,6 @@ Exception::GetLocation() const
return location.forget();
}
already_AddRefed<nsISupports>
Exception::GetInner() const
{
nsCOMPtr<nsIException> inner = mInner;
return inner.forget();
}
already_AddRefed<nsISupports>
Exception::GetData() const
{
@@ -632,25 +610,6 @@ DOMException::ToString(nsACString& aReturn)
nsAutoCString location;
if (mInner) {
nsString filename;
mInner->GetFilename(filename);
if (!filename.IsEmpty()) {
uint32_t line_nr = 0;
mInner->GetLineNumber(&line_nr);
char *temp = PR_smprintf("%s Line: %d",
NS_ConvertUTF16toUTF8(filename).get(),
line_nr);
if (temp) {
location.Assign(temp);
PR_smprintf_free(temp);
}
}
}
if (location.IsEmpty()) {
location = defaultLocation;
}
-3
View File
@@ -83,8 +83,6 @@ public:
already_AddRefed<nsIStackFrame> GetLocation() const;
already_AddRefed<nsISupports> GetInner() const;
already_AddRefed<nsISupports> GetData() const;
void GetStack(nsAString& aStack, ErrorResult& aRv) const;
@@ -110,7 +108,6 @@ protected:
nsCOMPtr<nsISupports> mData;
nsString mFilename;
int mLineNumber;
nsCOMPtr<nsIException> mInner;
bool mInitialized;
bool mHoldingJSVal;
+60 -37
View File
@@ -312,36 +312,15 @@ AutoJSAPI::~AutoJSAPI()
{
if (mOwnErrorReporting) {
MOZ_ASSERT(NS_IsMainThread(), "See corresponding assertion in TakeOwnershipOfErrorReporting()");
ReportException();
// We need to do this _after_ processing the existing exception, because the
// JS engine can throw while doing that, and uses this bit to determine what
// to do in that case: squelch the exception if the bit is set, otherwise
// call the error reporter. Calling WarningOnlyErrorReporter with a
// non-warning will assert, so we need to make sure we do the former.
JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(mOldAutoJSAPIOwnsErrorReporting);
if (HasException()) {
// AutoJSAPI uses a JSAutoNullableCompartment, and may be in a null
// compartment when the destructor is called. However, the JS engine
// requires us to be in a compartment when we fetch the pending exception.
// In this case, we enter the privileged junk scope and don't dispatch any
// error events.
JS::Rooted<JSObject*> errorGlobal(cx(), JS::CurrentGlobalOrNull(cx()));
if (!errorGlobal)
errorGlobal = xpc::PrivilegedJunkScope();
JSAutoCompartment ac(cx(), errorGlobal);
nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal);
JS::Rooted<JS::Value> exn(cx());
js::ErrorReport jsReport(cx());
if (StealException(&exn) && jsReport.init(cx(), exn)) {
nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
xpcReport->Init(jsReport.report(), jsReport.message(),
nsContentUtils::IsCallerChrome(),
win ? win->WindowID() : 0);
if (win) {
DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn);
} else {
xpcReport->LogToConsole();
}
} else {
NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
}
}
}
if (mOldErrorReporter.isSome()) {
@@ -502,17 +481,61 @@ AutoJSAPI::TakeOwnershipOfErrorReporting()
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
}
void
AutoJSAPI::ReportException()
{
MOZ_ASSERT(OwnsErrorReporting(), "This is not our exception to report!");
if (!HasException()) {
return;
}
// AutoJSAPI uses a JSAutoNullableCompartment, and may be in a null
// compartment when the destructor is called. However, the JS engine
// requires us to be in a compartment when we fetch the pending exception.
// In this case, we enter the privileged junk scope and don't dispatch any
// error events.
JS::Rooted<JSObject*> errorGlobal(cx(), JS::CurrentGlobalOrNull(cx()));
if (!errorGlobal)
errorGlobal = xpc::PrivilegedJunkScope();
JSAutoCompartment ac(cx(), errorGlobal);
nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal);
JS::Rooted<JS::Value> exn(cx());
js::ErrorReport jsReport(cx());
if (StealException(&exn) && jsReport.init(cx(), exn)) {
nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
xpcReport->Init(jsReport.report(), jsReport.message(),
nsContentUtils::IsCallerChrome(),
win ? win->WindowID() : 0);
if (win) {
DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn);
} else {
xpcReport->LogToConsole();
}
} else {
NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
}
}
bool
AutoJSAPI::PeekException(JS::MutableHandle<JS::Value> aVal)
{
MOZ_ASSERT_IF(mIsMainThread, CxPusherIsStackTop());
MOZ_ASSERT(HasException());
MOZ_ASSERT(js::GetContextCompartment(cx()));
if (!JS_GetPendingException(cx(), aVal)) {
return false;
}
return true;
}
bool
AutoJSAPI::StealException(JS::MutableHandle<JS::Value> aVal)
{
MOZ_ASSERT(CxPusherIsStackTop());
MOZ_ASSERT(HasException());
MOZ_ASSERT(js::GetContextCompartment(cx()));
if (!JS_GetPendingException(cx(), aVal)) {
return false;
}
JS_ClearPendingException(cx());
return true;
if (!PeekException(aVal)) {
return false;
}
JS_ClearPendingException(cx());
return true;
}
AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
+11
View File
@@ -273,6 +273,9 @@ public:
// while keeping the old behavior as the default.
void TakeOwnershipOfErrorReporting();
bool OwnsErrorReporting() { return mOwnErrorReporting; }
// If HasException, report it. Otherwise, a no-op. This must be
// called only if OwnsErrorReporting().
void ReportException();
bool HasException() const {
MOZ_ASSERT(CxPusherIsStackTop());
@@ -287,6 +290,14 @@ public:
// into the current compartment.
bool StealException(JS::MutableHandle<JS::Value> aVal);
// Peek the current exception from the JS engine, without stealing it.
// Callers must ensure that HasException() is true, and that cx() is in a
// non-null compartment.
//
// Note that this fails if and only if we OOM while wrapping the exception
// into the current compartment.
bool PeekException(JS::MutableHandle<JS::Value> aVal);
void ClearException() {
MOZ_ASSERT(CxPusherIsStackTop());
JS_ClearPendingException(cx());
+1
View File
@@ -12413,6 +12413,7 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
// New script entry point required, due to the "Create a script" sub-step of
// http://www.whatwg.org/specs/web-apps/current-work/#timer-initialization-steps
AutoEntryScript entryScript(this, true, aScx->GetNativeContext());
entryScript.TakeOwnershipOfErrorReporting();
JS::CompileOptions options(entryScript.cx());
options.setFileAndLine(filename, lineNo)
.setVersion(JSVERSION_DEFAULT);
+6 -59
View File
@@ -98,41 +98,6 @@ nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext)
return innerWindowID;
}
void
nsJSUtils::ReportPendingException(JSContext *aContext)
{
if (JS_IsExceptionPending(aContext)) {
bool saved = JS_SaveFrameChain(aContext);
{
// JS_SaveFrameChain set the compartment of aContext to null, so we need
// to enter a compartment. The question is, which one? We don't want to
// enter the original compartment of aContext (or the compartment of the
// current exception on aContext, for that matter) because when we
// JS_ReportPendingException the JS engine can try to duck-type the
// exception and produce a JSErrorReport. It will then pass that
// JSErrorReport to the error reporter on aContext, which might expose
// information from it to script via onerror handlers. So it's very
// important that the duck typing happen in the same compartment as the
// onerror handler. In practice, that's the compartment of the window (or
// otherwise default global) of aContext, so use that here.
nsIScriptContext* scx = GetScriptContextFromJSContext(aContext);
JS::Rooted<JSObject*> scope(aContext);
scope = scx ? scx->GetWindowProxy() : nullptr;
if (!scope) {
// The SafeJSContext has no default object associated with it.
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aContext == nsContentUtils::GetSafeJSContext());
scope = xpc::UnprivilegedJunkScope(); // Usage approved by bholley
}
JSAutoCompartment ac(aContext, scope);
JS_ReportPendingException(aContext);
}
if (saved) {
JS_RestoreFrameChain(aContext);
}
}
}
nsresult
nsJSUtils::CompileFunction(AutoJSAPI& jsapi,
JS::AutoObjectVector& aScopeChain,
@@ -199,12 +164,11 @@ nsJSUtils::EvaluateString(JSContext* aCx,
PROFILER_LABEL("nsJSUtils", "EvaluateString",
js::ProfileEntry::Category::JS);
MOZ_ASSERT(JS::ContextOptionsRef(aCx).autoJSAPIOwnsErrorReporting(),
"Caller must own error reporting");
MOZ_ASSERT_IF(aCompileOptions.versionSet,
aCompileOptions.version != JSVERSION_UNKNOWN);
MOZ_ASSERT_IF(aEvaluateOptions.coerceToString, !aCompileOptions.noScriptRval);
MOZ_ASSERT_IF(!aEvaluateOptions.reportUncaught, !aCompileOptions.noScriptRval);
// Note that the above assert means that if aCompileOptions.noScriptRval then
// also aEvaluateOptions.reportUncaught.
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
MOZ_ASSERT(aSrcBuf.get());
MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aEvaluationGlobal) ==
@@ -225,13 +189,6 @@ nsJSUtils::EvaluateString(JSContext* aCx,
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
NS_ENSURE_TRUE(ssm->ScriptAllowed(aEvaluationGlobal), NS_OK);
mozilla::Maybe<AutoDontReportUncaught> dontReport;
if (!aEvaluateOptions.reportUncaught) {
// We need to prevent AutoLastFrameCheck from reporting and clearing
// any pending exceptions.
dontReport.emplace(aCx);
}
bool ok = true;
// Scope the JSAutoCompartment so that we can later wrap the return value
// into the caller's cx.
@@ -275,24 +232,14 @@ nsJSUtils::EvaluateString(JSContext* aCx,
}
if (!ok) {
if (aEvaluateOptions.reportUncaught) {
ReportPendingException(aCx);
if (!aCompileOptions.noScriptRval) {
aRetValue.setUndefined();
}
} else {
rv = JS_IsExceptionPending(aCx) ? NS_ERROR_FAILURE
: NS_ERROR_OUT_OF_MEMORY;
JS::Rooted<JS::Value> exn(aCx);
JS_GetPendingException(aCx, &exn);
MOZ_ASSERT(!aCompileOptions.noScriptRval); // we asserted this on entry
aRetValue.set(exn);
JS_ClearPendingException(aCx);
rv = NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW;
if (!aCompileOptions.noScriptRval) {
aRetValue.setUndefined();
}
}
// Wrap the return value into whatever compartment aCx was in.
if (!aCompileOptions.noScriptRval) {
if (ok && !aCompileOptions.noScriptRval) {
if (!JS_WrapValue(aCx, aRetValue)) {
return NS_ERROR_OUT_OF_MEMORY;
}
+3 -15
View File
@@ -52,13 +52,6 @@ public:
*/
static uint64_t GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext);
/**
* Report a pending exception on aContext, if any. Note that this
* can be called when the context has a JS stack. If that's the
* case, the stack will be set aside before reporting the exception.
*/
static void ReportPendingException(JSContext *aContext);
static nsresult CompileFunction(mozilla::dom::AutoJSAPI& jsapi,
JS::AutoObjectVector& aScopeChain,
JS::CompileOptions& aOptions,
@@ -70,12 +63,10 @@ public:
struct MOZ_STACK_CLASS EvaluateOptions {
bool coerceToString;
bool reportUncaught;
JS::AutoObjectVector scopeChain;
explicit EvaluateOptions(JSContext* cx)
: coerceToString(false)
, reportUncaught(true)
, scopeChain(cx)
{}
@@ -83,16 +74,13 @@ public:
coerceToString = aCoerce;
return *this;
}
EvaluateOptions& setReportUncaught(bool aReport) {
reportUncaught = aReport;
return *this;
}
};
// aEvaluationGlobal is the global to evaluate in. The return value
// will then be wrapped back into the compartment aCx is in when
// this function is called.
// this function is called. For all the EvaluateString overloads,
// the JSContext must come from an AutoJSAPI that has had
// TakeOwnershipOfErrorReporting() called on it.
static nsresult EvaluateString(JSContext* aCx,
const nsAString& aScript,
JS::Handle<JSObject*> aEvaluationGlobal,
+1
View File
@@ -1138,6 +1138,7 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
// New script entry point required, due to the "Create a script" sub-step of
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
AutoEntryScript entryScript(globalObject, true, context->GetNativeContext());
entryScript.TakeOwnershipOfErrorReporting();
JS::Rooted<JSObject*> global(entryScript.cx(),
globalObject->GetGlobalJSObject());
+15 -14
View File
@@ -180,12 +180,8 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
// And now we're ready to go.
mCx = cx;
// Make sure the JS engine doesn't report exceptions we want to re-throw
if ((mCompartment && mExceptionHandling == eRethrowContentExceptions) ||
mExceptionHandling == eRethrowExceptions) {
mSavedJSContextOptions = JS::ContextOptionsRef(cx);
JS::ContextOptionsRef(cx).setDontReportUncaught(true);
}
// Make sure the JS engine doesn't report exceptions we want to re-throw.
mAutoEntryScript->TakeOwnershipOfErrorReporting();
}
bool
@@ -251,18 +247,18 @@ CallbackObject::CallSetup::~CallSetup()
// Now, if we have a JSContext, report any pending errors on it, unless we
// were told to re-throw them.
if (mCx) {
bool needToDealWithException = JS_IsExceptionPending(mCx);
bool needToDealWithException = mAutoEntryScript->HasException();
if ((mCompartment && mExceptionHandling == eRethrowContentExceptions) ||
mExceptionHandling == eRethrowExceptions) {
// Restore the old context options
JS::ContextOptionsRef(mCx) = mSavedJSContextOptions;
mErrorResult.MightThrowJSException();
MOZ_ASSERT(mAutoEntryScript->OwnsErrorReporting());
if (needToDealWithException) {
JS::Rooted<JS::Value> exn(mCx);
if (JS_GetPendingException(mCx, &exn) &&
if (mAutoEntryScript->PeekException(&exn) &&
ShouldRethrowException(exn)) {
mAutoEntryScript->ClearException();
MOZ_ASSERT(!mAutoEntryScript->HasException());
mErrorResult.ThrowJSException(mCx, exn);
JS_ClearPendingException(mCx);
needToDealWithException = false;
}
}
@@ -270,7 +266,7 @@ CallbackObject::CallSetup::~CallSetup()
if (needToDealWithException) {
// Either we're supposed to report our exceptions, or we're supposed to
// re-throw them but we failed to JS_GetPendingException. Either way,
// re-throw them but we failed to get the exception value. Either way,
// just report the pending exception, if any.
//
// We don't use nsJSUtils::ReportPendingException here because all it
@@ -281,7 +277,9 @@ CallbackObject::CallSetup::~CallSetup()
// screw up our compartment, which is exactly what we do not want.
//
// XXXbz FIXME: bug 979525 means we don't always JS_SaveFrameChain here,
// so we need to go ahead and do that.
// so we need to go ahead and do that. This is also the reason we don't
// just rely on ~AutoJSAPI reporting the exception for us. I think if we
// didn't need to JS_SaveFrameChain here, we could just rely on that.
JS::Rooted<JSObject*> oldGlobal(mCx, JS::CurrentGlobalOrNull(mCx));
MOZ_ASSERT(oldGlobal, "How can we not have a global here??");
bool saved = JS_SaveFrameChain(mCx);
@@ -292,7 +290,10 @@ CallbackObject::CallSetup::~CallSetup()
MOZ_ASSERT(!JS::DescribeScriptedCaller(mCx),
"Our comment above about JS_SaveFrameChain having been "
"called is a lie?");
JS_ReportPendingException(mCx);
// Note that we don't JS_ReportPendingException here because we want to
// go through our AutoEntryScript's reporting mechanism instead, since
// it currently owns error reporting.
mAutoEntryScript->ReportException();
}
if (saved) {
JS_RestoreFrameChain(mCx);
-1
View File
@@ -218,7 +218,6 @@ protected:
// we should re-throw them.
ErrorResult& mErrorResult;
const ExceptionHandling mExceptionHandling;
JS::ContextOptions mSavedJSContextOptions;
const bool mIsMainThread;
};
};
+1
View File
@@ -59,3 +59,4 @@ skip-if = debug == false
skip-if = debug == false
[test_worker_UnwrapArg.html]
[test_crossOriginWindowSymbolAccess.html]
[test_callback_exceptions.html]
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test for ...</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
promise_test(function(t) {
var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, JSON.parse);
return promise_rejects(t, new SyntaxError,
Promise.resolve().then(iterator.nextNode.bind(iterator)));
}, "Trying to use JSON.parse as filter should throw a catchable SyntaxError exception even when the filter is invoked async");
promise_test(function(t) {
return promise_rejects(t, new SyntaxError, Promise.resolve('{').then(JSON.parse));
}, "Trying to use JSON.parse as a promise callback should allow the next promise to handle the resulting exception.");
</script>
+6 -9
View File
@@ -249,6 +249,10 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
// http://www.whatwg.org/specs/web-apps/current-work/#javascript-protocol
AutoEntryScript entryScript(innerGlobal, true,
scriptContext->GetNativeContext());
// We want to make sure we report any exceptions that happen before we
// return, since whatever happens inside our execution shouldn't affect any
// other scripts that might happen to be running.
entryScript.TakeOwnershipOfErrorReporting();
JSContext* cx = entryScript.cx();
JS::Rooted<JSObject*> globalJSObject(cx, innerGlobal->GetGlobalJSObject());
NS_ENSURE_TRUE(globalJSObject, NS_ERROR_UNEXPECTED);
@@ -276,20 +280,13 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
rv = nsJSUtils::EvaluateString(cx, NS_ConvertUTF8toUTF16(script),
globalJSObject, options, evalOptions, &v);
// If there's an error on cx as a result of that call, report
// it now -- either we're just running under the event loop,
// so we shouldn't propagate JS exceptions out of here, or we
// can't be sure that our caller is JS (and if it's not we'll
// lose the error), or it might be JS that then proceeds to
// cause an error of its own (which will also make us lose
// this error).
::JS_ReportPendingException(cx);
if (NS_FAILED(rv) || !(v.isString() || v.isUndefined())) {
return NS_ERROR_MALFORMED_URI;
} else if (v.isUndefined()) {
return NS_ERROR_DOM_RETVAL_UNDEFINED;
} else {
MOZ_ASSERT(rv != NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW,
"How did we get a non-undefined return value?");
nsAutoJSString result;
if (!result.init(cx, v)) {
return NS_ERROR_OUT_OF_MEMORY;
+1
View File
@@ -1508,6 +1508,7 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result)
}
dom::AutoEntryScript aes(win);
aes.TakeOwnershipOfErrorReporting();
JSContext* cx = aes.cx();
JS::Rooted<JSObject*> obj(cx, nsNPObjWrapper::GetNewOrUsed(npp, cx, npobj));
-2
View File
@@ -52,8 +52,6 @@ interface ExceptionMembers
// this was only ever usefully available to chrome JS.
[ChromeOnly]
readonly attribute StackFrame? location;
// An inner exception that triggered this, if available.
readonly attribute nsISupports? inner;
// Arbitary data for the implementation.
readonly attribute nsISupports? data;
+7
View File
@@ -405,6 +405,7 @@ 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 entryScript(globalObject, true);
entryScript.TakeOwnershipOfErrorReporting();
JSContext* cx = entryScript.cx();
NS_ASSERTION(!::JS_IsExceptionPending(cx),
@@ -440,6 +441,12 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
return rv;
}
if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW) {
// Report the exception now, before we try using the JSContext for
// the JS_DefineUCProperty call.
entryScript.ReportException();
}
// Now, enter the node's compartment, wrap the eval result, and define it on
// the bound node.
JSAutoCompartment ac2(cx, aBoundNode);
+8
View File
@@ -229,6 +229,14 @@ ReportError(JSContext* cx, const char* message, JSErrorReport* reportp,
if (js_ErrorToException(cx, message, reportp, callback, userRef)) {
return;
}
/*
* The AutoJSAPI error reporter only allows warnings to be reported so
* just ignore this error rather than try to report it.
*/
if (cx->options().autoJSAPIOwnsErrorReporting() && !JSREPORT_IS_WARNING(reportp->flags))
return;
}
/*
+6
View File
@@ -607,6 +607,12 @@ js_ErrorToException(JSContext* cx, const char* message, JSErrorReport* reportp,
static bool
IsDuckTypedErrorObject(JSContext* cx, HandleObject exnObject, const char** filename_strp)
{
/*
* This function is called from ErrorReport::init and so should not generate
* any new exceptions.
*/
AutoClearPendingException acpe(cx);
bool found;
if (!JS_HasProperty(cx, exnObject, js_message_str, &found) || !found)
return false;
+14
View File
@@ -116,4 +116,18 @@ ExnTypeFromProtoKey(JSProtoKey key)
return type;
}
class AutoClearPendingException
{
JSContext *cx;
public:
explicit AutoClearPendingException(JSContext *cxArg)
: cx(cxArg)
{ }
~AutoClearPendingException() {
cx->clearPendingException();
}
};
#endif /* jsexn_h */
+2 -3
View File
@@ -7,7 +7,7 @@
#include "nsISupports.idl"
#include "nsIException.idl"
[scriptable, uuid(dd250248-2586-4ec1-a68f-8d14ef452517)]
[scriptable, uuid(875e6645-e762-4da6-9ec8-bf19ab0050df)]
interface nsIXPCException : nsIException
{
// inherits methods from nsIException
@@ -16,8 +16,7 @@ interface nsIXPCException : nsIException
in nsresult aResult,
in AUTF8String aName,
in nsIStackFrame aLocation,
in nsISupports aData,
in nsIException aInner);
in nsISupports aData);
};
/* this goes into the C++ header verbatim. */
+6
View File
@@ -529,6 +529,12 @@
* the second assignment throws NS_SUCCESS_DOM_NO_OPERATION.
*/
ERROR(NS_SUCCESS_DOM_NO_OPERATION, SUCCESS(1)),
/*
* A success code that indicates that evaluating a string of JS went
* just fine except it threw an exception.
*/
ERROR(NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW, SUCCESS(2)),
#undef MODULE
+1 -3
View File
@@ -12,7 +12,7 @@
[ptr] native JSContext(JSContext);
[scriptable, uuid(4ed5cd87-401a-425a-8d8d-c28fbc1e88b2)]
[scriptable, uuid(4371b5bf-6845-487f-8d9d-3f1e4a9badd2)]
interface nsIStackFrame : nsISupports
{
// see nsIProgrammingLanguage for list of language consts
@@ -69,8 +69,6 @@ interface nsIException : nsISupports
// A stack trace, if available.
readonly attribute nsIStackFrame location;
// An inner exception that triggered this, if available.
readonly attribute nsIException inner;
// Arbitary data for the implementation.
readonly attribute nsISupports data;