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:
Philip Chimento 2020-05-13 16:10:47 +00:00
parent 5606c63575
commit d6b8de58f7
8 changed files with 47 additions and 59 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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.

View File

@ -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);

View File

@ -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());

View File

@ -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;
}