Bug 1325381 - Fix crash with script constructed ExtendableEvent().waitUntil(). r=bkelly
authorCatalin Badea <catalin.badea392@gmail.com>
Thu, 22 Dec 2016 12:27:00 -0500
changeset 457724 920ef0f4af8999b69da071c184eaf1af7485020f
parent 457723 7177f9bb9d9392fbddddf61beb951cffd0f7013d
child 457725 ede3130bf486e9c38f061fb3ee7139446664641b
push id40874
push userbmo:kmckinley@mozilla.com
push dateMon, 09 Jan 2017 19:01:26 +0000
reviewersbkelly
bugs1325381
milestone53.0a1
Bug 1325381 - Fix crash with script constructed ExtendableEvent().waitUntil(). r=bkelly
dom/workers/ServiceWorkerEvents.cpp
testing/web-platform/tests/service-workers/service-worker/extendable-event-async-waituntil.https.html
testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-async-waituntil.js
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -910,17 +910,19 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Fetch
 ExtendableEvent::ExtendableEvent(EventTarget* aOwner)
   : Event(aOwner, nullptr, nullptr)
 {
 }
 
 bool
 ExtendableEvent::WaitOnPromise(Promise& aPromise)
 {
-  MOZ_ASSERT(mExtensionsHandler);
+  if (!mExtensionsHandler) {
+    return false;
+  }
   return mExtensionsHandler->WaitOnPromise(aPromise);
 }
 
 void
 ExtendableEvent::SetKeepAliveHandler(ExtensionsHandler* aExtensionsHandler)
 {
   MOZ_ASSERT(!mExtensionsHandler);
   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
--- a/testing/web-platform/tests/service-workers/service-worker/extendable-event-async-waituntil.https.html
+++ b/testing/web-platform/tests/service-workers/service-worker/extendable-event-async-waituntil.https.html
@@ -68,15 +68,18 @@ async_test(msg_event_test.bind(this, 'cu
 // The promise handler will queue a new microtask after the check for new
 // extensions was performed.
 async_test(msg_event_test.bind(this, 'current-extension-expired-same-microtask-turn-extra'),
   'Test calling waitUntil at the end of the microtask turn throws');
 
 async_test(msg_event_test.bind(this, 'current-extension-expired-different-task'),
   'Test calling waitUntil after the current extension expired in a different task fails');
 
+async_test(msg_event_test.bind(this, 'script-extendable-event'),
+  'Test calling waitUntil on a script constructed ExtendableEvent throws exception');
+
 async_test(function(t) {
     var testBody = function(worker) {
       return with_iframe('./resources/pending-respondwith-async-waituntil/dummy.html');
     }
     runTest(t, 'pending-respondwith-async-waituntil', testBody);
   }, 'Test calling waitUntil asynchronously with pending respondWith promise.');
 </script>
--- a/testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-async-waituntil.js
+++ b/testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-async-waituntil.js
@@ -37,16 +37,19 @@ self.addEventListener('message', functio
         event.waitUntil(waitPromise);
         waitPromise.then(() => { return async_microtask_waituntil(event); })
           .then(reportResultExpecting('InvalidStateError'))
         break;
       case 'current-extension-expired-different-task':
         event.waitUntil(Promise.resolve());
         async_task_waituntil(event).then(reportResultExpecting('InvalidStateError'));
         break;
+      case 'script-extendable-event':
+        new_event_waituntil().then(reportResultExpecting('InvalidStateError'));
+        break;
     }
     event.source.postMessage('ACK');
   });
 
 self.addEventListener('fetch', function(event) {
     var resolveFetch;
     let response = new Promise((res) => { resolveFetch = res; });
     event.respondWith(response);
@@ -68,16 +71,28 @@ function sync_waituntil(event) {
         event.waitUntil(Promise.resolve());
         res('OK');
       } catch (error) {
         res(error.name);
       }
   });
 }
 
+function new_event_waituntil() {
+  return new Promise((res, rej) => {
+    try {
+      let e = new ExtendableEvent('foo');
+      e.waitUntil(new Promise(() => {}));
+      res('OK');
+    } catch (error) {
+      res(error.name);
+    }
+  });
+}
+
 function async_microtask_waituntil(event) {
   return new Promise((res, rej) => {
     Promise.resolve().then(() => {
       try {
         event.waitUntil(Promise.resolve());
         res('OK');
       } catch (error) {
         res(error.name);