diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index e76a7312a8ae..b91902217f21 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -31,6 +31,7 @@ #include "mozilla/dom/WorkletGlobalScope.h" #include "jsfriendapi.h" +#include "js/Exception.h" // JS::ExceptionStack #include "js/StructuredClone.h" #include "nsContentUtils.h" #include "nsGlobalWindow.h" @@ -555,13 +556,15 @@ void Promise::ReportRejectedPromise(JSContext* aCx, JS::HandleObject aPromise) { (NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, &unwrapped, exn)) || NS_SUCCEEDED(UNWRAP_OBJECT(Exception, &unwrapped, exn)))) { xpcReport->Init(aCx, exn, isChrome, innerWindowID); - } else if (report.init(aCx, unwrapped, - JS::ErrorReportBuilder::NoSideEffects)) { + } else { + JS::ExceptionStack exnStack(aCx, unwrapped, nullptr); + if (!report.init(aCx, exnStack, JS::ErrorReportBuilder::NoSideEffects)) { + JS_ClearPendingException(aCx); + return; + } + xpcReport->Init(report.report(), report.toStringResult().c_str(), isChrome, innerWindowID); - } else { - JS_ClearPendingException(aCx); - return; } } diff --git a/dom/serviceworkers/ServiceWorkerEvents.cpp b/dom/serviceworkers/ServiceWorkerEvents.cpp index 361ee926e235..63ea17fe2ae4 100644 --- a/dom/serviceworkers/ServiceWorkerEvents.cpp +++ b/dom/serviceworkers/ServiceWorkerEvents.cpp @@ -11,6 +11,7 @@ #include "ServiceWorker.h" #include "ServiceWorkerManager.h" #include "js/Conversions.h" +#include "js/Exception.h" // JS::ExceptionStack, JS::StealPendingExceptionStack #include "js/TypeDecls.h" #include "mozilla/Encoding.h" #include "mozilla/ErrorResult.h" @@ -500,16 +501,14 @@ class MOZ_STACK_CLASS AutoCancel { MOZ_ASSERT(!aRv.Failed()); // Let's take the pending exception. - JS::Rooted exn(aCx); - if (!JS_GetPendingException(aCx, &exn)) { + JS::ExceptionStack exnStack(aCx); + if (!JS::StealPendingExceptionStack(aCx, &exnStack)) { return; } - JS_ClearPendingException(aCx); - // Converting the exception in a JS::ErrorReportBuilder. JS::ErrorReportBuilder report(aCx); - if (!report.init(aCx, exn, JS::ErrorReportBuilder::WithSideEffects)) { + if (!report.init(aCx, exnStack, JS::ErrorReportBuilder::WithSideEffects)) { JS_ClearPendingException(aCx); return; } diff --git a/dom/serviceworkers/ServiceWorkerOp.cpp b/dom/serviceworkers/ServiceWorkerOp.cpp index a1f56c85193a..3401fae9c81d 100644 --- a/dom/serviceworkers/ServiceWorkerOp.cpp +++ b/dom/serviceworkers/ServiceWorkerOp.cpp @@ -8,6 +8,7 @@ #include +#include "js/Exception.h" // JS::ExceptionStack, JS::StealPendingExceptionStack #include "jsapi.h" #include "nsCOMPtr.h" @@ -1051,16 +1052,14 @@ class MOZ_STACK_CLASS FetchEventOp::AutoCancel { MOZ_ASSERT(!aRv.Failed()); // Let's take the pending exception. - JS::Rooted exn(aCx); - if (!JS_GetPendingException(aCx, &exn)) { + JS::ExceptionStack exnStack(aCx); + if (!JS::StealPendingExceptionStack(aCx, &exnStack)) { return; } - JS_ClearPendingException(aCx); - // Converting the exception in a JS::ErrorReportBuilder. JS::ErrorReportBuilder report(aCx); - if (!report.init(aCx, exn, JS::ErrorReportBuilder::WithSideEffects)) { + if (!report.init(aCx, exnStack, JS::ErrorReportBuilder::WithSideEffects)) { JS_ClearPendingException(aCx); return; } diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index 0fc74df0ecbd..0231de6c0918 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -31,6 +31,7 @@ #include "jsapi.h" #include "jsfriendapi.h" #include "js/CompilationAndEvaluation.h" +#include "js/Exception.h" #include "js/SourceText.h" #include "nsError.h" #include "nsContentPolicyUtils.h" @@ -2250,8 +2251,9 @@ void ScriptExecutorRunnable::LogExceptionToConsole( MOZ_ASSERT(!JS_IsExceptionPending(aCx)); MOZ_ASSERT(!mScriptLoader.mRv.Failed()); + JS::ExceptionStack exnStack(aCx, exn, nullptr); JS::ErrorReportBuilder report(aCx); - if (!report.init(aCx, exn, JS::ErrorReportBuilder::WithSideEffects)) { + if (!report.init(aCx, exnStack, JS::ErrorReportBuilder::WithSideEffects)) { JS_ClearPendingException(aCx); return; } diff --git a/js/public/ErrorReport.h b/js/public/ErrorReport.h index 621bf1d61636..e565ac4565bb 100644 --- a/js/public/ErrorReport.h +++ b/js/public/ErrorReport.h @@ -284,18 +284,14 @@ struct MOZ_STACK_CLASS JS_PUBLIC_API ErrorReportBuilder { * it has one.) * * Otherwise various attempts are made to derive JSErrorReport information - * from |exn| and from the current execution state. This process is + * from |exnStack| and from the current execution state. This process is * *definitely* inconsistent with any standard, and particulars of the * behavior implemented here generally shouldn't be relied upon. * - * To fill in information such as file-name or line number the (optional) - * stack for the pending exception can be used. For this first SavedFrame - * is used. - * * If the value of |sniffingBehavior| is |WithSideEffects|, some of these - * attempts *may* invoke user-configurable behavior when |exn| is an object: - * converting |exn| to a string, detecting and getting properties on |exn|, - * accessing |exn|'s prototype chain, and others are possible. Users *must* + * attempts *may* invoke user-configurable behavior when the exception is an + * object: converting it to a string, detecting and getting its properties, + * accessing its prototype chain, and others are possible. Users *must* * tolerate |ErrorReportBuilder::init| potentially having arbitrary effects. * Any exceptions thrown by these operations will be caught and silently * ignored, and "default" values will be substituted into the JSErrorReport. @@ -307,10 +303,6 @@ struct MOZ_STACK_CLASS JS_PUBLIC_API ErrorReportBuilder { * Unlike some functions involved in error handling, this function adheres * to the usual JSAPI return value error behavior. */ - bool init(JSContext* cx, JS::HandleValue exn, - SniffingBehavior sniffingBehavior, - JS::HandleObject fallbackStack = nullptr); - bool init(JSContext* cx, const JS::ExceptionStack& exnStack, SniffingBehavior sniffingBehavior); @@ -326,9 +318,9 @@ struct MOZ_STACK_CLASS JS_PUBLIC_API ErrorReportBuilder { // Returns false if we fail to actually populate the ErrorReport // for some reason (probably out of memory). bool populateUncaughtExceptionReportUTF8(JSContext* cx, - JS::HandleObject fallbackStack, ...); + JS::HandleObject stack, ...); bool populateUncaughtExceptionReportUTF8VA(JSContext* cx, - JS::HandleObject fallbackStack, + JS::HandleObject stack, va_list ap); // Reports exceptions from add-on scopes to telemetry. diff --git a/js/src/jsapi-tests/testPrintError.cpp b/js/src/jsapi-tests/testPrintError.cpp index 40d6279e3e1a..d9c869697f8e 100644 --- a/js/src/jsapi-tests/testPrintError.cpp +++ b/js/src/jsapi-tests/testPrintError.cpp @@ -47,12 +47,11 @@ BEGIN_TEST(testPrintError_Works) { CHECK(!execDontReport("throw null;", "testPrintError_Works.js", 3)); - JS::RootedValue exception(cx); - CHECK(JS_GetPendingException(cx, &exception)); - JS_ClearPendingException(cx); + JS::ExceptionStack exnStack(cx); + CHECK(JS::StealPendingExceptionStack(cx, &exnStack)); JS::ErrorReportBuilder builder(cx); - CHECK(builder.init(cx, exception, JS::ErrorReportBuilder::NoSideEffects)); + CHECK(builder.init(cx, exnStack, JS::ErrorReportBuilder::NoSideEffects)); JS::PrintError(cx, buf.stream(), builder.toStringResult(), builder.report(), false); @@ -108,12 +107,11 @@ BEGIN_TEST(testPrintError_UTF16CodePoints) { CHECK(!execDontReport(utf8code, "testPrintError_UTF16CodePoints.js", 1)); - JS::RootedValue exception(cx); - CHECK(JS_GetPendingException(cx, &exception)); - JS_ClearPendingException(cx); + JS::ExceptionStack exnStack(cx); + CHECK(JS::StealPendingExceptionStack(cx, &exnStack)); JS::ErrorReportBuilder builder(cx); - CHECK(builder.init(cx, exception, JS::ErrorReportBuilder::NoSideEffects)); + CHECK(builder.init(cx, exnStack, JS::ErrorReportBuilder::NoSideEffects)); JS::PrintError(cx, buf.stream(), builder.toStringResult(), builder.report(), false); diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 482b5c92089f..1f4367c1a93c 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -473,19 +473,13 @@ JS::ErrorReportBuilder::~ErrorReportBuilder() = default; bool JS::ErrorReportBuilder::init(JSContext* cx, const JS::ExceptionStack& exnStack, SniffingBehavior sniffingBehavior) { - return init(cx, exnStack.exception(), sniffingBehavior, exnStack.stack()); -} - -bool JS::ErrorReportBuilder::init(JSContext* cx, HandleValue exn, - SniffingBehavior sniffingBehavior, - HandleObject fallbackStack) { MOZ_ASSERT(!cx->isExceptionPending()); MOZ_ASSERT(!reportp); - if (exn.isObject()) { + if (exnStack.exception().isObject()) { // Because ToString below could error and an exception object could become // unrooted, we must root our exception object, if any. - exnObject = &exn.toObject(); + exnObject = &exnStack.exception().toObject(); reportp = ErrorFromException(cx, exnObject); } @@ -495,9 +489,10 @@ bool JS::ErrorReportBuilder::init(JSContext* cx, HandleValue exn, RootedString str(cx); if (reportp) { str = ErrorReportToString(cx, exnObject, reportp, sniffingBehavior); - } else if (exn.isSymbol()) { + } else if (exnStack.exception().isSymbol()) { RootedValue strVal(cx); - if (js::SymbolDescriptiveString(cx, exn.toSymbol(), &strVal)) { + if (js::SymbolDescriptiveString(cx, exnStack.exception().toSymbol(), + &strVal)) { str = strVal.toString(); } else { str = nullptr; @@ -505,7 +500,7 @@ bool JS::ErrorReportBuilder::init(JSContext* cx, HandleValue exn, } else if (exnObject && sniffingBehavior == NoSideEffects) { str = cx->names().Object; } else { - str = js::ToString(cx, exn); + str = js::ToString(cx, exnStack.exception()); } if (!str) { @@ -617,7 +612,8 @@ bool JS::ErrorReportBuilder::init(JSContext* cx, HandleValue exn, // // but without the reporting bits. Instead it just puts all // the stuff we care about in our ownedReport and message_. - if (!populateUncaughtExceptionReportUTF8(cx, fallbackStack, utf8Message)) { + if (!populateUncaughtExceptionReportUTF8(cx, exnStack.stack(), + utf8Message)) { // Just give up. We're out of memory or something; not much we can // do here. return false; @@ -630,23 +626,23 @@ bool JS::ErrorReportBuilder::init(JSContext* cx, HandleValue exn, } bool JS::ErrorReportBuilder::populateUncaughtExceptionReportUTF8( - JSContext* cx, HandleObject fallbackStack, ...) { + JSContext* cx, HandleObject stack, ...) { va_list ap; - va_start(ap, fallbackStack); - bool ok = populateUncaughtExceptionReportUTF8VA(cx, fallbackStack, ap); + va_start(ap, stack); + bool ok = populateUncaughtExceptionReportUTF8VA(cx, stack, ap); va_end(ap); return ok; } bool JS::ErrorReportBuilder::populateUncaughtExceptionReportUTF8VA( - JSContext* cx, HandleObject fallbackStack, va_list ap) { + JSContext* cx, HandleObject stack, va_list ap) { new (&ownedReport) JSErrorReport(); ownedReport.isWarning_ = false; ownedReport.errorNumber = JSMSG_UNCAUGHT_EXCEPTION; bool skippedAsync; RootedSavedFrame frame( - cx, UnwrapSavedFrame(cx, cx->realm()->principals(), fallbackStack, + cx, UnwrapSavedFrame(cx, cx->realm()->principals(), stack, SavedFrameSelfHosted::Exclude, skippedAsync)); if (frame) { filename = StringToNewUTF8CharsZ(cx, *frame->getSource()); diff --git a/netwerk/base/ProxyAutoConfig.cpp b/netwerk/base/ProxyAutoConfig.cpp index 2f509419888a..37c6035aa75d 100644 --- a/netwerk/base/ProxyAutoConfig.cpp +++ b/netwerk/base/ProxyAutoConfig.cpp @@ -397,14 +397,13 @@ class MOZ_STACK_CLASS AutoPACErrorReporter { if (!JS_IsExceptionPending(mCx)) { return; } - JS::RootedValue exn(mCx); - if (!JS_GetPendingException(mCx, &exn)) { + JS::ExceptionStack exnStack(mCx); + if (!JS::StealPendingExceptionStack(mCx, &exnStack)) { return; } - JS_ClearPendingException(mCx); JS::ErrorReportBuilder report(mCx); - if (!report.init(mCx, exn, JS::ErrorReportBuilder::WithSideEffects)) { + if (!report.init(mCx, exnStack, JS::ErrorReportBuilder::WithSideEffects)) { JS_ClearPendingException(mCx); return; }