mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-25 20:01:50 +00:00
Bug 1629293 - Make JS::ErrorReportBuilder::init exclusively support JS::ExceptionStack. r=evilpie,mccr8
Differential Revision: https://phabricator.services.mozilla.com/D73522
This commit is contained in:
parent
5606c63575
commit
d6b8de58f7
@ -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,14 +556,16 @@ 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)) {
|
||||
xpcReport->Init(report.report(), report.toStringResult().c_str(),
|
||||
isChrome, innerWindowID);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Now post an event to do the real reporting async
|
||||
|
@ -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<JS::Value> 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;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#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<JS::Value> 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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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<CanGC>(cx, exn);
|
||||
str = js::ToString<CanGC>(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());
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user