Bug 1398974: Follow-up: Disconnect StreamFilters when closing extension context. r=me
authorKris Maglione <maglione.k@gmail.com>
Tue, 12 Sep 2017 18:55:24 -0700
changeset 430130 4f6d9ea5a49e003309f5f92ff155accb91c2f474
parent 430129 6ff73d0599c56ec91210cd1a936aa85e9597153e
child 430131 a8d6f6fd7bda07666155c8c9288c6d6bbf417fcf
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1398974
milestone57.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 1398974: Follow-up: Disconnect StreamFilters when closing extension context. r=me If we don't do this explicitly, the channel is automatically disconnected when it's GCed. However, if we start shutdown while a stream is being processed, the stream may not be GCed before we shut down the parent process's message loop. In that case, we get a shutdown crash because the StreamFilterParent's data channel is still open when we shut down its message loop. Explicitly disconnecting the StreamFilter when the context is closed prevents this, since app shutdown is automatically blocked on extension shutdown, and extension shutdown explicitly closes all extant contexts. MozReview-Commit-ID: 5JPrSUooq1j
toolkit/components/extensions/ExtensionCommon.jsm
toolkit/components/extensions/ext-c-webRequest.js
--- a/toolkit/components/extensions/ExtensionCommon.jsm
+++ b/toolkit/components/extensions/ExtensionCommon.jsm
@@ -1260,17 +1260,17 @@ class SchemaAPIManager extends EventEmit
    * @returns {object} A sandbox that is used as the global by `loadScript`.
    */
   _createExtGlobal() {
     let global = Cu.Sandbox(Services.scriptSecurityManager.getSystemPrincipal(), {
       wantXrays: false,
       sandboxName: `Namespace of ext-*.js scripts for ${this.processType} (from: resource://gre/modules/ExtensionCommon.jsm)`,
     });
 
-    Object.assign(global, {global, Cc, Ci, Cu, Cr, XPCOMUtils, ChromeWorker, ExtensionAPI, ExtensionCommon, MatchPattern, MatchPatternSet, StructuredCloneHolder, extensions: this});
+    Object.assign(global, {global, Cc, Ci, Cu, Cr, XPCOMUtils, ChromeUtils, ChromeWorker, ExtensionAPI, ExtensionCommon, MatchPattern, MatchPatternSet, StructuredCloneHolder, extensions: this});
 
     Cu.import("resource://gre/modules/AppConstants.jsm", global);
 
     XPCOMUtils.defineLazyGetter(global, "console", getConsole);
 
     XPCOMUtils.defineLazyModuleGetters(global, {
       ExtensionUtils: "resource://gre/modules/ExtensionUtils.jsm",
       XPCOMUtils: "resource://gre/modules/XPCOMUtils.jsm",
--- a/toolkit/components/extensions/ext-c-webRequest.js
+++ b/toolkit/components/extensions/ext-c-webRequest.js
@@ -1,18 +1,35 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 this.webRequest = class extends ExtensionAPI {
   getAPI(context) {
+    let filters = new WeakSet();
+
+    context.callOnClose({
+      close() {
+        for (let filter of ChromeUtils.nondeterministicGetWeakSetKeys(filters)) {
+          try {
+            filter.disconnect();
+          } catch (e) {
+            // Ignore.
+          }
+        }
+      },
+    });
+
     return {
       webRequest: {
         filterResponseData(requestId) {
           requestId = parseInt(requestId, 10);
 
-          return context.cloneScope.StreamFilter.create(
+          let streamFilter = context.cloneScope.StreamFilter.create(
             requestId, context.extension.id);
+
+          filters.add(streamFilter);
+          return streamFilter;
         },
       },
     };
   }
 };