Bug 1398601 - Fix subscript loader when using JSM global sharing draft
authorTed Campbell <tcampbell@mozilla.com>
Sun, 10 Sep 2017 14:23:32 -0400
changeset 664083 10cdd94404a218b27c15f0645d8729fba0889891
parent 664082 ae66d061f6358df228a7bcfabb9f193acb303492
child 664084 9d3481f3e0d8b9ad66ecb55c7b901d514c09b619
push id79624
push userbmo:tcampbell@mozilla.com
push dateWed, 13 Sep 2017 18:23:23 +0000
bugs1398601
milestone57.0a1
Bug 1398601 - Fix subscript loader when using JSM global sharing When using the subscript loader with JSM global sharing, it was possible that subscript would pollute the global of all JSMs in the sharing. MozReview-Commit-ID: 1ah5JUAZwBA
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/loader/mozJSSubScriptLoader.cpp
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -441,19 +441,24 @@ mozJSComponentLoader::LoadModule(FileLoc
 }
 
 void
 mozJSComponentLoader::FindTargetObject(JSContext* aCx,
                                        MutableHandleObject aTargetObject)
 {
     aTargetObject.set(js::GetJSMEnvironmentOfScriptedCaller(aCx));
 
-    // The above could fail if the scripted caller is not a
-    // component/JSM (it could be a DOM scope, for instance).
-    if (!aTargetObject) {
+    // The above could fail if the scripted caller is not a component/JSM (it
+    // could be a DOM scope, for instance).
+    //
+    // If the target object was not in the JSM shared global, return the global
+    // instead. This is needed when calling the subscript loader within a frame
+    // script, since it the FrameScript NSVO will have been found.
+    if (!aTargetObject ||
+        !IsLoaderGlobal(js::GetGlobalForObjectCrossCompartment(aTargetObject))) {
         aTargetObject.set(CurrentGlobalOrNull(aCx));
     }
 }
 
 // This requires that the keys be strings and the values be pointers.
 template <class Key, class Data, class UserData>
 static size_t
 SizeOfTableExcludingThis(const nsBaseHashtable<Key, Data, UserData>& aTable,
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -188,34 +188,50 @@ EvalScript(JSContext* cx,
            bool startupCache,
            bool preloadCache,
            MutableHandleScript script)
 {
     if (JS_IsGlobalObject(targetObj)) {
         if (!JS::CloneAndExecuteScript(cx, script, retval)) {
             return false;
         }
+    } else if (js::IsJSMEnvironment(targetObj)) {
+        if (!ExecuteInJSMEnvironment(cx, script, targetObj)) {
+            return false;
+        }
+        retval.setUndefined();
     } else {
         JS::AutoObjectVector envChain(cx);
         if (!envChain.append(targetObj)) {
             return false;
         }
-        if (loadScope != targetObj &&
-            loadScope &&
-            !JS_IsGlobalObject(loadScope))
-        {
-            MOZ_DIAGNOSTIC_ASSERT(js::GetObjectCompartment(loadScope) ==
-                                  js::GetObjectCompartment(targetObj));
-
-            if (!envChain.append(loadScope)) {
+        if (!loadScope) {
+            // A null loadScope means we are cross-compartment. In this case, we
+            // should check the target isn't in the JSM loader shared-global or
+            // we will contaiminate all JSMs in the compartment.
+            //
+            // NOTE: If loadScope is already a shared-global JSM, we can't
+            // determine which JSM the target belongs to and have to assume it
+            // is in our JSM.
+            JSObject* targetGlobal = js::GetGlobalForObjectCrossCompartment(targetObj);
+            MOZ_DIAGNOSTIC_ASSERT(!mozJSComponentLoader::Get()->IsLoaderGlobal(targetGlobal),
+                                  "Don't load subscript into target in a shared-global JSM");
+            if (!JS::CloneAndExecuteScript(cx, envChain, script, retval)) {
                 return false;
             }
-        }
-        if (!JS::CloneAndExecuteScript(cx, envChain, script, retval)) {
-            return false;
+        } else if (JS_IsGlobalObject(loadScope)) {
+            if (!JS::CloneAndExecuteScript(cx, envChain, script, retval)) {
+                return false;
+            }
+        } else {
+            MOZ_ASSERT(js::IsJSMEnvironment(loadScope));
+            if (!js::ExecuteInJSMEnvironment(cx, script, loadScope, envChain)) {
+                return false;
+            }
+            retval.setUndefined();
         }
     }
 
     JSAutoCompartment rac(cx, targetObj);
     if (!JS_WrapValue(cx, retval)) {
         return false;
     }