Bug 1330018 - Ensure we always unwrap CpowEntries. r=bholley,billm
authorAndrew McCreight <continuation@gmail.com>
Fri, 13 Jan 2017 13:50:35 -0800
changeset 463137 9ca73fb60c36714d16b9a74cb36e5d80f4162f65
parent 462810 77c56a2901b317ab2949c75e064ae8a8b998cd7f
child 463138 ce90a9d52e86c1edc7e194a23eabc1548e4dc104
push id41967
push userbmo:miket@mozilla.com
push dateWed, 18 Jan 2017 15:17:32 +0000
reviewersbholley, billm
bugs1330018
milestone53.0a1
Bug 1330018 - Ensure we always unwrap CpowEntries. r=bholley,billm We can drop async messages that contain CPOWs, which can cause us to leak them either until we successfully send a CPOW or forever, depending on the direction of the message. This is causing intermittent leaks until shutdown with e10s-multi. MozReview-Commit-ID: 3iIaIBZKZR2
js/ipc/CrossProcessObjectWrappers.h
js/ipc/JavaScriptShared.cpp
--- a/js/ipc/CrossProcessObjectWrappers.h
+++ b/js/ipc/CrossProcessObjectWrappers.h
@@ -44,21 +44,24 @@ class CPOWManager
 };
 
 class CrossProcessCpowHolder : public CpowHolder
 {
   public:
     CrossProcessCpowHolder(dom::CPOWManagerGetter* managerGetter,
                            const InfallibleTArray<CpowEntry>& cpows);
 
+    ~CrossProcessCpowHolder();
+
     bool ToObject(JSContext* cx, JS::MutableHandleObject objp);
 
   private:
     CPOWManager* js_;
     const InfallibleTArray<CpowEntry>& cpows_;
+    bool unwrapped_;
 };
 
 CPOWManager*
 CPOWManagerFor(PJavaScriptParent* aParent);
 
 CPOWManager*
 CPOWManagerFor(PJavaScriptChild* aChild);
 
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -645,26 +645,48 @@ JavaScriptShared::fromObjectOrNullVarian
         return nullptr;
 
     return fromObjectVariant(cx, objVar.get_ObjectVariant());
 }
 
 CrossProcessCpowHolder::CrossProcessCpowHolder(dom::CPOWManagerGetter* managerGetter,
                                                const InfallibleTArray<CpowEntry>& cpows)
   : js_(nullptr),
-    cpows_(cpows)
+    cpows_(cpows),
+    unwrapped_(false)
 {
     // Only instantiate the CPOW manager if we might need it later.
     if (cpows.Length())
         js_ = managerGetter->GetCPOWManager();
 }
 
+CrossProcessCpowHolder::~CrossProcessCpowHolder()
+{
+    if (cpows_.Length() && !unwrapped_) {
+        // This should only happen if a message manager message
+        // containing CPOWs gets ignored for some reason. We need to
+        // unwrap every incoming CPOW in this process to ensure that
+        // the corresponding part of the CPOW in the other process
+        // will eventually be collected. The scope for this object
+        // doesn't really matter, because it immediately becomes
+        // garbage.
+        AutoJSAPI jsapi;
+        if (!jsapi.Init(xpc::PrivilegedJunkScope()))
+            return;
+        JSContext* cx = jsapi.cx();
+        JS::Rooted<JSObject*> cpows(cx);
+        js_->Unwrap(cx, cpows_, &cpows);
+    }
+}
+
 bool
 CrossProcessCpowHolder::ToObject(JSContext* cx, JS::MutableHandleObject objp)
 {
+    unwrapped_ = true;
+
     if (!cpows_.Length())
         return true;
 
     return js_->Unwrap(cx, cpows_, objp);
 }
 
 bool
 JavaScriptShared::Unwrap(JSContext* cx, const InfallibleTArray<CpowEntry>& aCpows,