Bug 1020226 - Fix unhandled Promise rejection handling in workers. r=khuey
authorNikhil Marathe <nsm.nikhil@gmail.com>
Thu, 05 Jun 2014 12:21:56 -0700
changeset 206097 fc7aa8ef354087c8a496e19d6d08d4cc4fb72910
parent 206096 b8e17d034a6f5f20c32b85e92909c15d7c19a47b
child 206098 8635607dedea28daa0cad89bcb09fbc492035289
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1020226
milestone32.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 1020226 - Fix unhandled Promise rejection handling in workers. r=khuey * * * Bug 1020226 - Test case to crash browser when using Promises on workers. r=khuey
dom/promise/Promise.cpp
dom/workers/test/bug1020226_frame.html
dom/workers/test/bug1020226_worker.js
dom/workers/test/mochitest.ini
dom/workers/test/test_bug1020226.html
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -1203,19 +1203,21 @@ Promise::RunResolveTask(JS::Handle<JS::V
       !mHadRejectCallback &&
       !NS_IsMainThread()) {
     WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(worker);
     worker->AssertIsOnWorkerThread();
 
     mFeature = new PromiseReportRejectFeature(this);
     if (NS_WARN_IF(!worker->AddFeature(worker->GetJSContext(), mFeature))) {
+      // To avoid a false RemoveFeature().
+      mFeature = nullptr;
       // Worker is shutting down, report rejection immediately since it is
       // unlikely that reject callbacks will be added after this point.
-      MaybeReportRejected();
+      MaybeReportRejectedOnce();
     }
   }
 
   RunTask();
 }
 
 void
 Promise::RemoveFeature()
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/bug1020226_frame.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1020226
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1020226</title>
+</head>
+<body>
+
+<script type="application/javascript">
+  var worker = new Worker("bug1020226_worker.js");
+  worker.onmessage = function(e) {
+    window.parent.postMessage("loaded", "*");
+  }
+</script>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/bug1020226_worker.js
@@ -0,0 +1,11 @@
+var p = new Promise(function(resolve, reject) {
+  // This causes a runnable to be queued.
+  reject(new Error());
+  postMessage("loaded");
+
+  // This prevents that runnable from running until the window calls terminate(),
+  // at which point the worker goes into the Canceling state and then an
+  // AddFeature() is attempted, which fails, which used to result in multiple
+  // calls to the error reporter, one after the worker's context had been GCed.
+  while (true);
+});
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -1,12 +1,14 @@
 [DEFAULT]
 support-files =
   WorkerTest_badworker.js
   atob_worker.js
+  bug1020226_worker.js
+  bug1020226_frame.html
   clearTimeouts_worker.js
   closeOnGC_server.sjs
   closeOnGC_worker.js
   close_worker.js
   content_worker.js
   console_worker.js
   consoleReplaceable_worker.js
   csp_worker.js
@@ -73,16 +75,17 @@ support-files =
   subdir/relativeLoad_sub_import.js
 
 [test_404.html]
 [test_atob.html]
 [test_blobConstructor.html]
 [test_blobWorkers.html]
 [test_bug949946.html]
 [test_bug1010784.html]
+[test_bug1020226.html]
 [test_chromeWorker.html]
 [test_clearTimeouts.html]
 [test_close.html]
 [test_closeOnGC.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #bug 881404 # b2g-debug(times out) b2g-desktop(times out)
 [test_console.html]
 [test_consoleReplaceable.html]
 [test_contentWorker.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_bug1020226.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1020226
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1020226</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1020226">Mozilla Bug 1020226</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+<iframe id="iframe" src="bug1020226_frame.html" onload="finishTest();">
+</iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+function finishTest() {
+  document.getElementById("iframe").onload = null;
+  window.onmessage = function(e) {
+    info("Got message");
+    document.getElementById("iframe").src = "about:blank";
+    // We aren't really interested in the test, it shouldn't crash when the
+    // worker is GCed later.
+    ok(true, "Should not crash");
+    SimpleTest.finish();
+  };
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>