Bug 1486130: Fix reporting of unhandled DOMException rejection values. r=smaug
authorKris Maglione <maglione.k@gmail.com>
Thu, 23 Aug 2018 14:01:04 -0700
changeset 488763 7ccc1c8a7abeefd54bc4cf9a5d0eef23681c924a
parent 488762 24a110d82c0f52e757878dbfa7b0c62f2bd0b2fa
child 488764 275602e7cfcdd2e9c7326bbd190525cd92f21832
push id9734
push usershindli@mozilla.com
push dateThu, 30 Aug 2018 12:18:07 +0000
treeherdermozilla-beta@71c71ab3afae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1486130
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1486130: Fix reporting of unhandled DOMException rejection values. r=smaug Differential Revision: https://phabricator.services.mozilla.com/D4264
browser/components/payments/test/browser/head.js
dom/promise/Promise.cpp
dom/promise/tests/unit/.eslintrc.js
dom/promise/tests/unit/test_promise_unhandled_rejection.js
dom/promise/tests/unit/xpcshell.ini
--- a/browser/components/payments/test/browser/head.js
+++ b/browser/components/payments/test/browser/head.js
@@ -338,16 +338,20 @@ add_task(async function setup_head() {
     if (msg.category == "CSP_CSPViolationWithURI" && msg.errorMessage.includes("at inline")) {
       // Ignore unknown CSP error.
       return;
     }
     if (msg.message && msg.message.match(/docShell is null.*BrowserUtils.jsm/)) {
       // Bug 1478142 - Console spam from the Find Toolbar.
       return;
     }
+    if (msg.errorMessage == "AbortError: The operation was aborted. " &&
+        msg.sourceName == "" && msg.lineNumber == 0) {
+      return;
+    }
     ok(false, msg.message || msg.errorMessage);
   });
   await setupFormAutofillStorage();
   registerCleanupFunction(function cleanup() {
     paymentSrv.cleanup();
     cleanupFormAutofillStorage();
     Services.prefs.clearUserPref(RESPONSE_TIMEOUT_PREF);
     Services.prefs.clearUserPref(SAVE_CREDITCARD_DEFAULT_PREF);
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -528,31 +528,40 @@ void
 Promise::ReportRejectedPromise(JSContext* aCx, JS::HandleObject aPromise)
 {
   MOZ_ASSERT(!js::IsWrapper(aPromise));
 
   MOZ_ASSERT(JS::GetPromiseState(aPromise) == JS::PromiseState::Rejected);
 
   JS::Rooted<JS::Value> result(aCx, JS::GetPromiseResult(aPromise));
 
-  js::ErrorReport report(aCx);
-  if (!report.init(aCx, result, js::ErrorReport::NoSideEffects)) {
-    JS_ClearPendingException(aCx);
-    return;
-  }
-
   RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
   bool isMainThread = MOZ_LIKELY(NS_IsMainThread());
   bool isChrome = isMainThread ? nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(aPromise))
                                : IsCurrentThreadRunningChromeWorker();
   nsGlobalWindowInner* win = isMainThread
     ? xpc::WindowGlobalOrNull(aPromise)
     : nullptr;
-  xpcReport->Init(report.report(), report.toStringResult().c_str(), isChrome,
-                  win ? win->AsInner()->WindowID() : 0);
+
+  js::ErrorReport report(aCx);
+  if (report.init(aCx, result, js::ErrorReport::NoSideEffects)) {
+    xpcReport->Init(report.report(), report.toStringResult().c_str(), isChrome,
+                    win ? win->AsInner()->WindowID() : 0);
+  } else {
+    JS_ClearPendingException(aCx);
+
+    RefPtr<Exception> exn;
+    if (result.isObject() &&
+        (NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, &result, exn)) ||
+         NS_SUCCEEDED(UNWRAP_OBJECT(Exception, &result, exn)))) {
+      xpcReport->Init(aCx, exn, isChrome, win ? win->AsInner()->WindowID() : 0);
+    } else {
+      return;
+    }
+  }
 
   // Now post an event to do the real reporting async
   RefPtr<nsIRunnable> event = new AsyncErrorReporter(xpcReport);
   if (win) {
     win->Dispatch(mozilla::TaskCategory::Other, event.forget());
   } else {
     NS_DispatchToMainThread(event);
   }
new file mode 100644
--- /dev/null
+++ b/dom/promise/tests/unit/.eslintrc.js
@@ -0,0 +1,5 @@
+module.exports = {
+  "extends": [
+    "plugin:mozilla/xpcshell-test",
+  ],
+};
new file mode 100644
--- /dev/null
+++ b/dom/promise/tests/unit/test_promise_unhandled_rejection.js
@@ -0,0 +1,38 @@
+"use strict";
+
+// Tests that unhandled promise rejections generate the appropriate
+// console messages.
+
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
+ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm");
+
+PromiseTestUtils.expectUncaughtRejection(/could not be cloned/);
+
+add_task(async function test_unhandled_dom_exception() {
+  let sandbox = Cu.Sandbox(Services.scriptSecurityManager.getSystemPrincipal());
+  sandbox.StructuredCloneHolder = StructuredCloneHolder;
+
+  let filename = "resource://foo/Bar.jsm";
+
+  let {messages} = await AddonTestUtils.promiseConsoleOutput(async () => {
+    let code = `new Promise(() => {
+      new StructuredCloneHolder(() => {});
+    });`;
+
+    Cu.evalInSandbox(code, sandbox, null, filename, 1);
+
+    // We need two trips through the event loop for this error to be reported.
+    await new Promise(executeSoon);
+    await new Promise(executeSoon);
+  });
+
+  equal(messages.length, 1, "Got one console message");
+
+  let [msg] = messages;
+  ok(msg instanceof Ci.nsIScriptError, "Message is a script error");
+  equal(msg.sourceName, filename, "Got expected filename");
+  equal(msg.lineNumber, 2, "Got expected line number");
+  equal(msg.errorMessage, "DataCloneError: The object could not be cloned.",
+        "Got expected error message");
+});
--- a/dom/promise/tests/unit/xpcshell.ini
+++ b/dom/promise/tests/unit/xpcshell.ini
@@ -1,4 +1,5 @@
 [DEFAULT]
 head =
 
 [test_monitor_uncaught.js]
+[test_promise_unhandled_rejection.js]