LCOV - code coverage report
Current view: top level - js/xpconnect/src - XPCWrappedNativeScope.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 132 497 26.6 %
Date: 2017-07-14 16:53:18 Functions: 15 42 35.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* Class used to manage the wrapped native objects within a JS scope. */
       8             : 
       9             : #include "xpcprivate.h"
      10             : #include "XPCWrapper.h"
      11             : #include "nsContentUtils.h"
      12             : #include "nsCycleCollectionNoteRootCallback.h"
      13             : #include "ExpandedPrincipal.h"
      14             : #include "mozilla/MemoryReporting.h"
      15             : #include "mozilla/Preferences.h"
      16             : #include "nsIAddonInterposition.h"
      17             : #include "nsIXULRuntime.h"
      18             : 
      19             : #include "mozilla/dom/BindingUtils.h"
      20             : 
      21             : using namespace mozilla;
      22             : using namespace xpc;
      23             : using namespace JS;
      24             : 
      25             : /***************************************************************************/
      26             : 
      27             : XPCWrappedNativeScope* XPCWrappedNativeScope::gScopes = nullptr;
      28             : XPCWrappedNativeScope* XPCWrappedNativeScope::gDyingScopes = nullptr;
      29             : bool XPCWrappedNativeScope::gShutdownObserverInitialized = false;
      30             : XPCWrappedNativeScope::InterpositionMap* XPCWrappedNativeScope::gInterpositionMap = nullptr;
      31             : InterpositionWhitelistArray* XPCWrappedNativeScope::gInterpositionWhitelists = nullptr;
      32             : XPCWrappedNativeScope::AddonSet* XPCWrappedNativeScope::gAllowCPOWAddonSet = nullptr;
      33             : 
      34           0 : NS_IMPL_ISUPPORTS(XPCWrappedNativeScope::ClearInterpositionsObserver, nsIObserver)
      35             : 
      36             : NS_IMETHODIMP
      37           0 : XPCWrappedNativeScope::ClearInterpositionsObserver::Observe(nsISupports* subject,
      38             :                                                             const char* topic,
      39             :                                                             const char16_t* data)
      40             : {
      41           0 :     MOZ_ASSERT(strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
      42             : 
      43             :     // The interposition map holds strong references to interpositions, which
      44             :     // may themselves be involved in cycles. We need to drop these strong
      45             :     // references before the cycle collector shuts down. Otherwise we'll
      46             :     // leak. This observer always runs before CC shutdown.
      47           0 :     if (gInterpositionMap) {
      48           0 :         delete gInterpositionMap;
      49           0 :         gInterpositionMap = nullptr;
      50             :     }
      51             : 
      52           0 :     if (gInterpositionWhitelists) {
      53           0 :         delete gInterpositionWhitelists;
      54           0 :         gInterpositionWhitelists = nullptr;
      55             :     }
      56             : 
      57           0 :     if (gAllowCPOWAddonSet) {
      58           0 :         delete gAllowCPOWAddonSet;
      59           0 :         gAllowCPOWAddonSet = nullptr;
      60             :     }
      61             : 
      62           0 :     nsContentUtils::UnregisterShutdownObserver(this);
      63           0 :     return NS_OK;
      64             : }
      65             : 
      66             : static bool
      67         293 : RemoteXULForbidsXBLScope(nsIPrincipal* aPrincipal, HandleObject aGlobal)
      68             : {
      69         293 :   MOZ_ASSERT(aPrincipal);
      70             : 
      71             :   // Certain singleton sandoxes are created very early in startup - too early
      72             :   // to call into AllowXULXBLForPrincipal. We never create XBL scopes for
      73             :   // sandboxes anway, and certainly not for these singleton scopes. So we just
      74             :   // short-circuit here.
      75         293 :   if (IsSandbox(aGlobal))
      76          25 :       return false;
      77             : 
      78             :   // AllowXULXBLForPrincipal will return true for system principal, but we
      79             :   // don't want that here.
      80         268 :   MOZ_ASSERT(nsContentUtils::IsInitialized());
      81         268 :   if (nsContentUtils::IsSystemPrincipal(aPrincipal))
      82         263 :       return false;
      83             : 
      84             :   // If this domain isn't whitelisted, we're done.
      85           5 :   if (!nsContentUtils::AllowXULXBLForPrincipal(aPrincipal))
      86           5 :       return false;
      87             : 
      88             :   // Check the pref to determine how we should behave.
      89           0 :   return !Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul", false);
      90             : }
      91             : 
      92         293 : XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext* cx,
      93         293 :                                              JS::HandleObject aGlobal)
      94         293 :       : mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_LENGTH)),
      95         293 :         mWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_LENGTH)),
      96             :         mComponents(nullptr),
      97             :         mNext(nullptr),
      98             :         mGlobalJSObject(aGlobal),
      99             :         mHasCallInterpositions(false),
     100             :         mIsContentXBLScope(false),
     101         879 :         mIsAddonScope(false)
     102             : {
     103             :     // add ourselves to the scopes list
     104             :     {
     105         293 :         MOZ_ASSERT(aGlobal);
     106         586 :         DebugOnly<const js::Class*> clasp = js::GetObjectClass(aGlobal);
     107         293 :         MOZ_ASSERT(clasp->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS |
     108             :                                    JSCLASS_HAS_PRIVATE) ||
     109             :                    mozilla::dom::IsDOMClass(clasp));
     110             : #ifdef DEBUG
     111       24755 :         for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
     112       24462 :             MOZ_ASSERT(aGlobal != cur->GetGlobalJSObjectPreserveColor(), "dup object");
     113             : #endif
     114             : 
     115         293 :         mNext = gScopes;
     116         293 :         gScopes = this;
     117             :     }
     118             : 
     119         293 :     MOZ_COUNT_CTOR(XPCWrappedNativeScope);
     120             : 
     121             :     // Create the compartment private.
     122         293 :     JSCompartment* c = js::GetObjectCompartment(aGlobal);
     123         293 :     MOZ_ASSERT(!JS_GetCompartmentPrivate(c));
     124         293 :     CompartmentPrivate* priv = new CompartmentPrivate(c);
     125         293 :     JS_SetCompartmentPrivate(c, priv);
     126             : 
     127             :     // Attach ourselves to the compartment private.
     128         293 :     priv->scope = this;
     129             : 
     130             :     // Determine whether we would allow an XBL scope in this situation.
     131             :     // In addition to being pref-controlled, we also disable XBL scopes for
     132             :     // remote XUL domains, _except_ if we have an additional pref override set.
     133         293 :     nsIPrincipal* principal = GetPrincipal();
     134         293 :     mAllowContentXBLScope = !RemoteXULForbidsXBLScope(principal, aGlobal);
     135             : 
     136             :     // Determine whether to use an XBL scope.
     137         293 :     mUseContentXBLScope = mAllowContentXBLScope;
     138         293 :     if (mUseContentXBLScope) {
     139         293 :       const js::Class* clasp = js::GetObjectClass(mGlobalJSObject);
     140         293 :       mUseContentXBLScope = !strcmp(clasp->name, "Window");
     141             :     }
     142         293 :     if (mUseContentXBLScope) {
     143           7 :       mUseContentXBLScope = principal && !nsContentUtils::IsSystemPrincipal(principal);
     144             :     }
     145             : 
     146         293 :     JSAddonId* addonId = JS::AddonIdOfObject(aGlobal);
     147         293 :     if (gInterpositionMap) {
     148           0 :         bool isSystem = nsContentUtils::IsSystemPrincipal(principal);
     149           0 :         bool waiveInterposition = priv->waiveInterposition;
     150           0 :         InterpositionMap::Ptr interposition = gInterpositionMap->lookup(addonId);
     151           0 :         if (!waiveInterposition && interposition) {
     152           0 :             MOZ_RELEASE_ASSERT(isSystem);
     153           0 :             mInterposition = interposition->value();
     154             :         }
     155             :         // We also want multiprocessCompatible add-ons to have a default interposition.
     156           0 :         if (!mInterposition && addonId && isSystem) {
     157             :           bool interpositionEnabled = mozilla::Preferences::GetBool(
     158           0 :             "extensions.interposition.enabled", false);
     159           0 :           if (interpositionEnabled) {
     160           0 :             mInterposition = do_GetService("@mozilla.org/addons/default-addon-shims;1");
     161           0 :             MOZ_ASSERT(mInterposition);
     162           0 :             UpdateInterpositionWhitelist(cx, mInterposition);
     163             :           }
     164             :         }
     165             :     }
     166             : 
     167         293 :     if (addonId) {
     168             :         // We forbid CPOWs unless they're specifically allowed.
     169          29 :         priv->allowCPOWs = gAllowCPOWAddonSet ? gAllowCPOWAddonSet->has(addonId) : false;
     170             :     }
     171         293 : }
     172             : 
     173             : // static
     174             : bool
     175           0 : XPCWrappedNativeScope::IsDyingScope(XPCWrappedNativeScope* scope)
     176             : {
     177           0 :     for (XPCWrappedNativeScope* cur = gDyingScopes; cur; cur = cur->mNext) {
     178           0 :         if (scope == cur)
     179           0 :             return true;
     180             :     }
     181           0 :     return false;
     182             : }
     183             : 
     184             : bool
     185         279 : XPCWrappedNativeScope::GetComponentsJSObject(JS::MutableHandleObject obj)
     186             : {
     187         558 :     AutoJSContext cx;
     188         279 :     if (!mComponents) {
     189         278 :         nsIPrincipal* p = GetPrincipal();
     190         278 :         bool system = nsXPConnect::SecurityManager()->IsSystemPrincipal(p);
     191         278 :         mComponents = system ? new nsXPCComponents(this)
     192         556 :                              : new nsXPCComponentsBase(this);
     193             :     }
     194             : 
     195         558 :     RootedValue val(cx);
     196         558 :     xpcObjectHelper helper(mComponents);
     197         558 :     bool ok = XPCConvert::NativeInterface2JSObject(&val, nullptr, helper,
     198             :                                                    nullptr, false,
     199         279 :                                                    nullptr);
     200         279 :     if (NS_WARN_IF(!ok))
     201           0 :         return false;
     202             : 
     203         279 :     if (NS_WARN_IF(!val.isObject()))
     204           0 :         return false;
     205             : 
     206             :     // The call to wrap() here is necessary even though the object is same-
     207             :     // compartment, because it applies our security wrapper.
     208         279 :     obj.set(&val.toObject());
     209         279 :     if (NS_WARN_IF(!JS_WrapObject(cx, obj)))
     210           0 :         return false;
     211         279 :     return true;
     212             : }
     213             : 
     214             : void
     215           1 : XPCWrappedNativeScope::ForcePrivilegedComponents()
     216             : {
     217           2 :     nsCOMPtr<nsIXPCComponents> c = do_QueryInterface(mComponents);
     218           1 :     if (!c)
     219           1 :         mComponents = new nsXPCComponents(this);
     220           1 : }
     221             : 
     222             : bool
     223         279 : XPCWrappedNativeScope::AttachComponentsObject(JSContext* aCx)
     224             : {
     225         558 :     RootedObject components(aCx);
     226         279 :     if (!GetComponentsJSObject(&components))
     227           0 :         return false;
     228             : 
     229         558 :     RootedObject global(aCx, GetGlobalJSObject());
     230         279 :     MOZ_ASSERT(js::IsObjectInContextCompartment(global, aCx));
     231             : 
     232             :     // The global Components property is non-configurable if it's a full
     233             :     // nsXPCComponents object. That way, if it's an nsXPCComponentsBase,
     234             :     // enableUniversalXPConnect can upgrade it later.
     235         279 :     unsigned attrs = JSPROP_READONLY | JSPROP_RESOLVING;
     236         558 :     nsCOMPtr<nsIXPCComponents> c = do_QueryInterface(mComponents);
     237         279 :     if (c)
     238         279 :         attrs |= JSPROP_PERMANENT;
     239             : 
     240         558 :     RootedId id(aCx, XPCJSContext::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS));
     241         279 :     return JS_DefinePropertyById(aCx, global, id, components, attrs);
     242             : }
     243             : 
     244             : static bool
     245           0 : CompartmentPerAddon()
     246             : {
     247             :     static bool initialized = false;
     248             :     static bool pref = false;
     249             : 
     250           0 :     if (!initialized) {
     251           0 :         pref = Preferences::GetBool("dom.compartment_per_addon", false) ||
     252           0 :                BrowserTabsRemoteAutostart();
     253           0 :         initialized = true;
     254             :     }
     255             : 
     256           0 :     return pref;
     257             : }
     258             : 
     259             : JSObject*
     260        2698 : XPCWrappedNativeScope::EnsureContentXBLScope(JSContext* cx)
     261             : {
     262        5396 :     JS::RootedObject global(cx, GetGlobalJSObject());
     263        2698 :     MOZ_ASSERT(js::IsObjectInContextCompartment(global, cx));
     264        2698 :     MOZ_ASSERT(!mIsContentXBLScope);
     265        2698 :     MOZ_ASSERT(strcmp(js::GetObjectClass(global)->name,
     266             :                       "nsXBLPrototypeScript compilation scope"));
     267             : 
     268             :     // If we already have a special XBL scope object, we know what to use.
     269        2698 :     if (mContentXBLScope)
     270           0 :         return mContentXBLScope;
     271             : 
     272             :     // If this scope doesn't need an XBL scope, just return the global.
     273        2698 :     if (!mUseContentXBLScope)
     274        2698 :         return global;
     275             : 
     276             :     // Set up the sandbox options. Note that we use the DOM global as the
     277             :     // sandboxPrototype so that the XBL scope can access all the DOM objects
     278             :     // it's accustomed to accessing.
     279             :     //
     280             :     // In general wantXrays shouldn't matter much here, but there are weird
     281             :     // cases when adopting bound content between same-origin globals where a
     282             :     // <destructor> in one content XBL scope sees anonymous content in another
     283             :     // content XBL scope. When that happens, we hit LookupBindingMember for an
     284             :     // anonymous element that lives in a content XBL scope, which isn't a tested
     285             :     // or audited codepath. So let's avoid hitting that case by opting out of
     286             :     // same-origin Xrays.
     287           0 :     SandboxOptions options;
     288           0 :     options.wantXrays = false;
     289           0 :     options.wantComponents = true;
     290           0 :     options.proto = global;
     291           0 :     options.sameZoneAs = global;
     292             : 
     293             :     // Use an ExpandedPrincipal to create asymmetric security.
     294           0 :     nsIPrincipal* principal = GetPrincipal();
     295           0 :     MOZ_ASSERT(!nsContentUtils::IsExpandedPrincipal(principal));
     296           0 :     nsTArray<nsCOMPtr<nsIPrincipal>> principalAsArray(1);
     297           0 :     principalAsArray.AppendElement(principal);
     298             :     RefPtr<ExpandedPrincipal> ep =
     299           0 :         ExpandedPrincipal::Create(principalAsArray,
     300           0 :                                   principal->OriginAttributesRef());
     301             : 
     302             :     // Create the sandbox.
     303           0 :     RootedValue v(cx);
     304           0 :     nsresult rv = CreateSandboxObject(cx, &v,
     305           0 :                                       static_cast<nsIExpandedPrincipal*>(ep),
     306           0 :                                       options);
     307           0 :     NS_ENSURE_SUCCESS(rv, nullptr);
     308           0 :     mContentXBLScope = &v.toObject();
     309             : 
     310             :     // Tag it.
     311           0 :     CompartmentPrivate::Get(js::UncheckedUnwrap(mContentXBLScope))->scope->mIsContentXBLScope = true;
     312             : 
     313             :     // Good to go!
     314           0 :     return mContentXBLScope;
     315             : }
     316             : 
     317             : bool
     318        5350 : XPCWrappedNativeScope::AllowContentXBLScope()
     319             : {
     320             :     // We only disallow XBL scopes in remote XUL situations.
     321        5350 :     MOZ_ASSERT_IF(!mAllowContentXBLScope,
     322             :                   nsContentUtils::AllowXULXBLForPrincipal(GetPrincipal()));
     323        5350 :     return mAllowContentXBLScope;
     324             : }
     325             : 
     326             : namespace xpc {
     327             : JSObject*
     328        2698 : GetXBLScope(JSContext* cx, JSObject* contentScopeArg)
     329             : {
     330        2698 :     MOZ_ASSERT(!IsInAddonScope(contentScopeArg));
     331             : 
     332        5396 :     JS::RootedObject contentScope(cx, contentScopeArg);
     333        5396 :     JSAutoCompartment ac(cx, contentScope);
     334        2698 :     JSObject* scope = CompartmentPrivate::Get(contentScope)->scope->EnsureContentXBLScope(cx);
     335        2698 :     NS_ENSURE_TRUE(scope, nullptr); // See bug 858642.
     336        2698 :     scope = js::UncheckedUnwrap(scope);
     337        2698 :     JS::ExposeObjectToActiveJS(scope);
     338        2698 :     return scope;
     339             : }
     340             : 
     341             : JSObject*
     342         230 : GetScopeForXBLExecution(JSContext* cx, HandleObject contentScope, JSAddonId* addonId)
     343             : {
     344         230 :     MOZ_RELEASE_ASSERT(!IsInAddonScope(contentScope));
     345             : 
     346         460 :     RootedObject global(cx, js::GetGlobalForObjectCrossCompartment(contentScope));
     347         230 :     if (IsInContentXBLScope(contentScope))
     348           0 :         return global;
     349             : 
     350         460 :     JSAutoCompartment ac(cx, contentScope);
     351         230 :     XPCWrappedNativeScope* nativeScope = CompartmentPrivate::Get(contentScope)->scope;
     352         230 :     bool isSystem = nsContentUtils::IsSystemPrincipal(nativeScope->GetPrincipal());
     353             : 
     354         460 :     RootedObject scope(cx);
     355         230 :     if (nativeScope->UseContentXBLScope())
     356           0 :         scope = nativeScope->EnsureContentXBLScope(cx);
     357         230 :     else if (addonId && CompartmentPerAddon() && isSystem)
     358           0 :         scope = nativeScope->EnsureAddonScope(cx, addonId);
     359             :     else
     360         230 :         scope = global;
     361             : 
     362         230 :     NS_ENSURE_TRUE(scope, nullptr); // See bug 858642.
     363         230 :     scope = js::UncheckedUnwrap(scope);
     364         230 :     JS::ExposeObjectToActiveJS(scope);
     365         230 :     return scope;
     366             : }
     367             : 
     368             : bool
     369        5350 : AllowContentXBLScope(JSCompartment* c)
     370             : {
     371        5350 :   XPCWrappedNativeScope* scope = CompartmentPrivate::Get(c)->scope;
     372        5350 :   return scope && scope->AllowContentXBLScope();
     373             : }
     374             : 
     375             : bool
     376         638 : UseContentXBLScope(JSCompartment* c)
     377             : {
     378         638 :   XPCWrappedNativeScope* scope = CompartmentPrivate::Get(c)->scope;
     379         638 :   return scope && scope->UseContentXBLScope();
     380             : }
     381             : 
     382             : void
     383           1 : ClearContentXBLScope(JSObject* global)
     384             : {
     385           1 :     CompartmentPrivate::Get(global)->scope->ClearContentXBLScope();
     386           1 : }
     387             : 
     388             : } /* namespace xpc */
     389             : 
     390             : JSObject*
     391           0 : XPCWrappedNativeScope::EnsureAddonScope(JSContext* cx, JSAddonId* addonId)
     392             : {
     393           0 :     JS::RootedObject global(cx, GetGlobalJSObject());
     394           0 :     MOZ_ASSERT(js::IsObjectInContextCompartment(global, cx));
     395           0 :     MOZ_ASSERT(!mIsContentXBLScope);
     396           0 :     MOZ_ASSERT(!mIsAddonScope);
     397           0 :     MOZ_ASSERT(addonId);
     398           0 :     MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(GetPrincipal()));
     399             : 
     400             :     // In bug 1092156, we found that add-on scopes don't work correctly when the
     401             :     // window navigates. The add-on global's prototype is an outer window, so,
     402             :     // after the navigation, looking up window properties in the add-on scope
     403             :     // will fail. However, in most cases where the window can be navigated, the
     404             :     // entire window is part of the add-on. To solve the problem, we avoid
     405             :     // returning an add-on scope for a window that is already tagged with the
     406             :     // add-on ID.
     407           0 :     if (AddonIdOfObject(global) == addonId)
     408           0 :         return global;
     409             : 
     410             :     // If we already have an addon scope object, we know what to use.
     411           0 :     for (size_t i = 0; i < mAddonScopes.Length(); i++) {
     412           0 :         if (JS::AddonIdOfObject(js::UncheckedUnwrap(mAddonScopes[i])) == addonId)
     413           0 :             return mAddonScopes[i];
     414             :     }
     415             : 
     416           0 :     SandboxOptions options;
     417           0 :     options.wantComponents = true;
     418           0 :     options.proto = global;
     419           0 :     options.sameZoneAs = global;
     420           0 :     options.addonId = JS::StringOfAddonId(addonId);
     421           0 :     options.writeToGlobalPrototype = true;
     422             : 
     423           0 :     RootedValue v(cx);
     424           0 :     nsresult rv = CreateSandboxObject(cx, &v, GetPrincipal(), options);
     425           0 :     NS_ENSURE_SUCCESS(rv, nullptr);
     426           0 :     mAddonScopes.AppendElement(&v.toObject());
     427             : 
     428           0 :     CompartmentPrivate::Get(js::UncheckedUnwrap(&v.toObject()))->scope->mIsAddonScope = true;
     429           0 :     return &v.toObject();
     430             : }
     431             : 
     432             : JSObject*
     433          39 : xpc::GetAddonScope(JSContext* cx, JS::HandleObject contentScope, JSAddonId* addonId)
     434             : {
     435          39 :     MOZ_RELEASE_ASSERT(!IsInAddonScope(contentScope));
     436             : 
     437          39 :     if (!addonId || !CompartmentPerAddon()) {
     438          39 :         return js::GetGlobalForObjectCrossCompartment(contentScope);
     439             :     }
     440             : 
     441           0 :     JSAutoCompartment ac(cx, contentScope);
     442           0 :     XPCWrappedNativeScope* nativeScope = CompartmentPrivate::Get(contentScope)->scope;
     443           0 :     if (nativeScope->GetPrincipal() != nsXPConnect::SystemPrincipal()) {
     444             :         // This can happen if, for example, Jetpack loads an unprivileged HTML
     445             :         // page from the add-on. It's not clear what to do there, so we just use
     446             :         // the normal global.
     447           0 :         return js::GetGlobalForObjectCrossCompartment(contentScope);
     448             :     }
     449           0 :     JSObject* scope = nativeScope->EnsureAddonScope(cx, addonId);
     450           0 :     NS_ENSURE_TRUE(scope, nullptr);
     451             : 
     452           0 :     scope = js::UncheckedUnwrap(scope);
     453           0 :     JS::ExposeObjectToActiveJS(scope);
     454           0 :     return scope;
     455             : }
     456             : 
     457           0 : XPCWrappedNativeScope::~XPCWrappedNativeScope()
     458             : {
     459           0 :     MOZ_COUNT_DTOR(XPCWrappedNativeScope);
     460             : 
     461             :     // We can do additional cleanup assertions here...
     462             : 
     463           0 :     MOZ_ASSERT(0 == mWrappedNativeMap->Count(), "scope has non-empty map");
     464           0 :     delete mWrappedNativeMap;
     465             : 
     466           0 :     MOZ_ASSERT(0 == mWrappedNativeProtoMap->Count(), "scope has non-empty map");
     467           0 :     delete mWrappedNativeProtoMap;
     468             : 
     469             :     // This should not be necessary, since the Components object should die
     470             :     // with the scope but just in case.
     471           0 :     if (mComponents)
     472           0 :         mComponents->mScope = nullptr;
     473             : 
     474             :     // XXX we should assert that we are dead or that xpconnect has shutdown
     475             :     // XXX might not want to do this at xpconnect shutdown time???
     476           0 :     mComponents = nullptr;
     477             : 
     478           0 :     if (mXrayExpandos.initialized())
     479           0 :         mXrayExpandos.destroy();
     480             : 
     481           0 :     JSContext* cx = dom::danger::GetJSContext();
     482           0 :     mGlobalJSObject.finalize(cx);
     483           0 : }
     484             : 
     485             : // static
     486             : void
     487           1 : XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(JSTracer* trc)
     488             : {
     489             :     // Do JS::TraceEdge for all wrapped natives with external references, as
     490             :     // well as any DOM expando objects.
     491         212 :     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
     492        4687 :         for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
     493        4476 :             auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
     494        4476 :             XPCWrappedNative* wrapper = entry->value;
     495        4476 :             if (wrapper->HasExternalReference() && !wrapper->IsWrapperExpired())
     496           2 :                 wrapper->TraceSelf(trc);
     497             :         }
     498             :     }
     499           1 : }
     500             : 
     501             : // static
     502             : void
     503           0 : XPCWrappedNativeScope::SuspectAllWrappers(nsCycleCollectionNoteRootCallback& cb)
     504             : {
     505           0 :     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
     506           0 :         for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
     507           0 :             static_cast<Native2WrappedNativeMap::Entry*>(i.Get())->value->Suspect(cb);
     508             :         }
     509             :     }
     510           0 : }
     511             : 
     512             : // static
     513             : void
     514           0 : XPCWrappedNativeScope::UpdateWeakPointersInAllScopesAfterGC()
     515             : {
     516             :     // If this is called from the finalization callback in JSGC_MARK_END then
     517             :     // JSGC_FINALIZE_END must always follow it calling
     518             :     // FinishedFinalizationPhaseOfGC and clearing gDyingScopes in
     519             :     // KillDyingScopes.
     520           0 :     MOZ_ASSERT(!gDyingScopes, "JSGC_MARK_END without JSGC_FINALIZE_END");
     521             : 
     522           0 :     XPCWrappedNativeScope** scopep = &gScopes;
     523           0 :     while (*scopep) {
     524           0 :         XPCWrappedNativeScope* cur = *scopep;
     525           0 :         cur->UpdateWeakPointersAfterGC();
     526           0 :         if (cur->mGlobalJSObject) {
     527           0 :             scopep = &cur->mNext;
     528             :         } else {
     529             :             // The scope's global is dead so move it to the dying scopes list.
     530           0 :             *scopep = cur->mNext;
     531           0 :             cur->mNext = gDyingScopes;
     532           0 :             gDyingScopes = cur;
     533             :         }
     534             :     }
     535           0 : }
     536             : 
     537             : static inline void
     538           0 : AssertSameCompartment(DebugOnly<JSCompartment*>& comp, JSObject* obj)
     539             : {
     540           0 :     MOZ_ASSERT_IF(obj, js::GetObjectCompartment(obj) == comp);
     541           0 : }
     542             : 
     543             : static inline void
     544           0 : AssertSameCompartment(DebugOnly<JSCompartment*>& comp, const JS::ObjectPtr& obj)
     545             : {
     546             : #ifdef DEBUG
     547           0 :     AssertSameCompartment(comp, obj.unbarrieredGet());
     548             : #endif
     549           0 : }
     550             : 
     551             : void
     552           0 : XPCWrappedNativeScope::UpdateWeakPointersAfterGC()
     553             : {
     554             :     // Sweep waivers.
     555           0 :     if (mWaiverWrapperMap)
     556           0 :         mWaiverWrapperMap->Sweep();
     557             : 
     558           0 :     if (!js::IsObjectZoneSweepingOrCompacting(mGlobalJSObject.unbarrieredGet()))
     559           0 :         return;
     560             : 
     561             :     // Update our pointer to the global object in case it was moved or
     562             :     // finalized.
     563           0 :     mGlobalJSObject.updateWeakPointerAfterGC();
     564           0 :     if (!mGlobalJSObject) {
     565           0 :         JSContext* cx = dom::danger::GetJSContext();
     566           0 :         mContentXBLScope.finalize(cx);
     567           0 :         for (size_t i = 0; i < mAddonScopes.Length(); i++)
     568           0 :             mAddonScopes[i].finalize(cx);
     569           0 :         GetWrappedNativeMap()->Clear();
     570           0 :         mWrappedNativeProtoMap->Clear();
     571           0 :         return;
     572             :     }
     573             : 
     574             :     DebugOnly<JSCompartment*> comp =
     575           0 :         js::GetObjectCompartment(mGlobalJSObject.unbarrieredGet());
     576             : 
     577             : #ifdef DEBUG
     578             :     // These are traced, so no updates are necessary.
     579           0 :     if (mContentXBLScope) {
     580           0 :         JSObject* prev = mContentXBLScope.unbarrieredGet();
     581           0 :         mContentXBLScope.updateWeakPointerAfterGC();
     582           0 :         MOZ_ASSERT(prev == mContentXBLScope.unbarrieredGet());
     583           0 :         AssertSameCompartment(comp, mContentXBLScope);
     584             :     }
     585           0 :     for (size_t i = 0; i < mAddonScopes.Length(); i++) {
     586           0 :         JSObject* prev = mAddonScopes[i].unbarrieredGet();
     587           0 :         mAddonScopes[i].updateWeakPointerAfterGC();
     588           0 :         MOZ_ASSERT(prev == mAddonScopes[i].unbarrieredGet());
     589           0 :         AssertSameCompartment(comp, mAddonScopes[i]);
     590             :     }
     591             : #endif
     592             : 
     593             :     // Sweep mWrappedNativeMap for dying flat JS objects. Moving has already
     594             :     // been handled by XPCWrappedNative::FlatJSObjectMoved.
     595           0 :     for (auto iter = GetWrappedNativeMap()->Iter(); !iter.Done(); iter.Next()) {
     596           0 :         auto entry = static_cast<Native2WrappedNativeMap::Entry*>(iter.Get());
     597           0 :         XPCWrappedNative* wrapper = entry->value;
     598           0 :         JSObject* obj = wrapper->GetFlatJSObjectPreserveColor();
     599           0 :         JS_UpdateWeakPointerAfterGCUnbarriered(&obj);
     600           0 :         MOZ_ASSERT(!obj || obj == wrapper->GetFlatJSObjectPreserveColor());
     601           0 :         AssertSameCompartment(comp, obj);
     602           0 :         if (!obj)
     603           0 :             iter.Remove();
     604             :     }
     605             : 
     606             :     // Sweep mWrappedNativeProtoMap for dying prototype JSObjects. Moving has
     607             :     // already been handled by XPCWrappedNativeProto::JSProtoObjectMoved.
     608           0 :     for (auto i = mWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
     609           0 :         auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get());
     610           0 :         JSObject* obj = entry->value->GetJSProtoObjectPreserveColor();
     611           0 :         JS_UpdateWeakPointerAfterGCUnbarriered(&obj);
     612           0 :         AssertSameCompartment(comp, obj);
     613           0 :         MOZ_ASSERT(!obj || obj == entry->value->GetJSProtoObjectPreserveColor());
     614           0 :         if (!obj)
     615           0 :             i.Remove();
     616             :     }
     617             : }
     618             : 
     619             : // static
     620             : void
     621           0 : XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs()
     622             : {
     623           0 :     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
     624           0 :         for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
     625           0 :             auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
     626           0 :             entry->value->SweepTearOffs();
     627             :         }
     628             :     }
     629           0 : }
     630             : 
     631             : // static
     632             : void
     633           0 : XPCWrappedNativeScope::KillDyingScopes()
     634             : {
     635           0 :     XPCWrappedNativeScope* cur = gDyingScopes;
     636           0 :     while (cur) {
     637           0 :         XPCWrappedNativeScope* next = cur->mNext;
     638           0 :         if (cur->mGlobalJSObject)
     639           0 :             CompartmentPrivate::Get(cur->mGlobalJSObject)->scope = nullptr;
     640           0 :         delete cur;
     641           0 :         cur = next;
     642             :     }
     643           0 :     gDyingScopes = nullptr;
     644           0 : }
     645             : 
     646             : //static
     647             : void
     648           0 : XPCWrappedNativeScope::SystemIsBeingShutDown()
     649             : {
     650           0 :     int liveScopeCount = 0;
     651             : 
     652             :     XPCWrappedNativeScope* cur;
     653             : 
     654             :     // First move all the scopes to the dying list.
     655             : 
     656           0 :     cur = gScopes;
     657           0 :     while (cur) {
     658           0 :         XPCWrappedNativeScope* next = cur->mNext;
     659           0 :         cur->mNext = gDyingScopes;
     660           0 :         gDyingScopes = cur;
     661           0 :         cur = next;
     662           0 :         liveScopeCount++;
     663             :     }
     664           0 :     gScopes = nullptr;
     665             : 
     666             :     // We're forcibly killing scopes, rather than allowing them to go away
     667             :     // when they're ready. As such, we need to do some cleanup before they
     668             :     // can safely be destroyed.
     669             : 
     670           0 :     for (cur = gDyingScopes; cur; cur = cur->mNext) {
     671             :         // Give the Components object a chance to try to clean up.
     672           0 :         if (cur->mComponents)
     673           0 :             cur->mComponents->SystemIsBeingShutDown();
     674             : 
     675             :         // Walk the protos first. Wrapper shutdown can leave dangling
     676             :         // proto pointers in the proto map.
     677           0 :         for (auto i = cur->mWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
     678           0 :             auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get());
     679           0 :             entry->value->SystemIsBeingShutDown();
     680           0 :             i.Remove();
     681             :         }
     682           0 :         for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
     683           0 :             auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
     684           0 :             XPCWrappedNative* wrapper = entry->value;
     685           0 :             if (wrapper->IsValid()) {
     686           0 :                 wrapper->SystemIsBeingShutDown();
     687             :             }
     688           0 :             i.Remove();
     689             :         }
     690             :     }
     691             : 
     692             :     // Now it is safe to kill all the scopes.
     693           0 :     KillDyingScopes();
     694           0 : }
     695             : 
     696             : 
     697             : /***************************************************************************/
     698             : 
     699             : JSObject*
     700        1181 : XPCWrappedNativeScope::GetExpandoChain(HandleObject target)
     701             : {
     702        1181 :     MOZ_ASSERT(ObjectScope(target) == this);
     703        1181 :     if (!mXrayExpandos.initialized())
     704        1181 :         return nullptr;
     705           0 :     return mXrayExpandos.lookup(target);
     706             : }
     707             : 
     708             : bool
     709           0 : XPCWrappedNativeScope::SetExpandoChain(JSContext* cx, HandleObject target,
     710             :                                        HandleObject chain)
     711             : {
     712           0 :     MOZ_ASSERT(ObjectScope(target) == this);
     713           0 :     MOZ_ASSERT(js::IsObjectInContextCompartment(target, cx));
     714           0 :     MOZ_ASSERT_IF(chain, ObjectScope(chain) == this);
     715           0 :     if (!mXrayExpandos.initialized() && !mXrayExpandos.init(cx))
     716           0 :         return false;
     717           0 :     return mXrayExpandos.put(cx, target, chain);
     718             : }
     719             : 
     720             : /* static */ bool
     721           0 : XPCWrappedNativeScope::SetAddonInterposition(JSContext* cx,
     722             :                                              JSAddonId* addonId,
     723             :                                              nsIAddonInterposition* interp)
     724             : {
     725           0 :     if (!gInterpositionMap) {
     726           0 :         gInterpositionMap = new InterpositionMap();
     727           0 :         bool ok = gInterpositionMap->init();
     728           0 :         NS_ENSURE_TRUE(ok, false);
     729             : 
     730           0 :         if (!gShutdownObserverInitialized) {
     731           0 :             gShutdownObserverInitialized = true;
     732           0 :             nsContentUtils::RegisterShutdownObserver(new ClearInterpositionsObserver());
     733             :         }
     734             :     }
     735           0 :     if (interp) {
     736           0 :         bool ok = gInterpositionMap->put(addonId, interp);
     737           0 :         NS_ENSURE_TRUE(ok, false);
     738           0 :         UpdateInterpositionWhitelist(cx, interp);
     739             :     } else {
     740           0 :         gInterpositionMap->remove(addonId);
     741             :     }
     742           0 :     return true;
     743             : }
     744             : 
     745             : /* static */ bool
     746           0 : XPCWrappedNativeScope::AllowCPOWsInAddon(JSContext* cx,
     747             :                                          JSAddonId* addonId,
     748             :                                          bool allow)
     749             : {
     750           0 :     if (!gAllowCPOWAddonSet) {
     751           0 :         gAllowCPOWAddonSet = new AddonSet();
     752           0 :         bool ok = gAllowCPOWAddonSet->init();
     753           0 :         NS_ENSURE_TRUE(ok, false);
     754             : 
     755           0 :         if (!gShutdownObserverInitialized) {
     756           0 :             gShutdownObserverInitialized = true;
     757           0 :             nsContentUtils::RegisterShutdownObserver(new ClearInterpositionsObserver());
     758             :         }
     759             :     }
     760           0 :     if (allow) {
     761           0 :         bool ok = gAllowCPOWAddonSet->put(addonId);
     762           0 :         NS_ENSURE_TRUE(ok, false);
     763             :     } else {
     764           0 :         gAllowCPOWAddonSet->remove(addonId);
     765             :     }
     766           0 :     return true;
     767             : }
     768             : 
     769             : nsCOMPtr<nsIAddonInterposition>
     770           0 : XPCWrappedNativeScope::GetInterposition()
     771             : {
     772           0 :     return mInterposition;
     773             : }
     774             : 
     775             : /* static */ InterpositionWhitelist*
     776           0 : XPCWrappedNativeScope::GetInterpositionWhitelist(nsIAddonInterposition* interposition)
     777             : {
     778           0 :     if (!gInterpositionWhitelists)
     779           0 :         return nullptr;
     780             : 
     781           0 :     InterpositionWhitelistArray& wls = *gInterpositionWhitelists;
     782           0 :     for (size_t i = 0; i < wls.Length(); i++) {
     783           0 :         if (wls[i].interposition == interposition)
     784           0 :             return &wls[i].whitelist;
     785             :     }
     786             : 
     787           0 :     return nullptr;
     788             : }
     789             : 
     790             : /* static */ bool
     791           0 : XPCWrappedNativeScope::UpdateInterpositionWhitelist(JSContext* cx,
     792             :                                                     nsIAddonInterposition* interposition)
     793             : {
     794             :     // We want to set the interpostion whitelist only once.
     795           0 :     InterpositionWhitelist* whitelist = GetInterpositionWhitelist(interposition);
     796           0 :     if (whitelist)
     797           0 :         return true;
     798             : 
     799             :     // The hashsets in gInterpositionWhitelists do not have a copy constructor so
     800             :     // a reallocation for the array will lead to a memory corruption. If you
     801             :     // need more interpositions, change the capacity of the array please.
     802             :     static const size_t MAX_INTERPOSITION = 8;
     803           0 :     if (!gInterpositionWhitelists)
     804           0 :         gInterpositionWhitelists = new InterpositionWhitelistArray(MAX_INTERPOSITION);
     805             : 
     806           0 :     MOZ_RELEASE_ASSERT(MAX_INTERPOSITION > gInterpositionWhitelists->Length() + 1);
     807           0 :     InterpositionWhitelistPair* newPair = gInterpositionWhitelists->AppendElement();
     808           0 :     newPair->interposition = interposition;
     809           0 :     if (!newPair->whitelist.init()) {
     810           0 :         JS_ReportOutOfMemory(cx);
     811           0 :         return false;
     812             :     }
     813             : 
     814           0 :     whitelist = &newPair->whitelist;
     815             : 
     816           0 :     RootedValue whitelistVal(cx);
     817           0 :     nsresult rv = interposition->GetWhitelist(&whitelistVal);
     818           0 :     if (NS_FAILED(rv)) {
     819           0 :         JS_ReportErrorASCII(cx, "Could not get the whitelist from the interposition.");
     820           0 :         return false;
     821             :     }
     822             : 
     823           0 :     if (!whitelistVal.isObject()) {
     824           0 :         JS_ReportErrorASCII(cx, "Whitelist must be an array.");
     825           0 :         return false;
     826             :     }
     827             : 
     828             :     // We want to enter the whitelist's compartment to avoid any wrappers.
     829             :     // To be on the safe side let's make sure that it's a system compartment
     830             :     // and we don't accidentally trigger some content function here by parsing
     831             :     // the whitelist object.
     832           0 :     RootedObject whitelistObj(cx, &whitelistVal.toObject());
     833           0 :     whitelistObj = js::UncheckedUnwrap(whitelistObj);
     834           0 :     if (!AccessCheck::isChrome(whitelistObj)) {
     835           0 :         JS_ReportErrorASCII(cx, "Whitelist must be from system scope.");
     836           0 :         return false;
     837             :     }
     838             : 
     839             :     {
     840           0 :         JSAutoCompartment ac(cx, whitelistObj);
     841             : 
     842             :         bool isArray;
     843           0 :         if (!JS_IsArrayObject(cx, whitelistObj, &isArray))
     844           0 :             return false;
     845             : 
     846           0 :         if (!isArray) {
     847           0 :             JS_ReportErrorASCII(cx, "Whitelist must be an array.");
     848           0 :             return false;
     849             :         }
     850             : 
     851             :         uint32_t length;
     852           0 :         if (!JS_GetArrayLength(cx, whitelistObj, &length))
     853           0 :             return false;
     854             : 
     855           0 :         for (uint32_t i = 0; i < length; i++) {
     856           0 :             RootedValue idval(cx);
     857           0 :             if (!JS_GetElement(cx, whitelistObj, i, &idval))
     858           0 :                 return false;
     859             : 
     860           0 :             if (!idval.isString()) {
     861           0 :                 JS_ReportErrorASCII(cx, "Whitelist must contain strings only.");
     862           0 :                 return false;
     863             :             }
     864             : 
     865           0 :             RootedString str(cx, idval.toString());
     866           0 :             str = JS_AtomizeAndPinJSString(cx, str);
     867           0 :             if (!str) {
     868           0 :                 JS_ReportErrorASCII(cx, "String internization failed.");
     869           0 :                 return false;
     870             :             }
     871             : 
     872             :             // By internizing the id's we ensure that they won't get
     873             :             // GCed so we can use them as hash keys.
     874           0 :             jsid id = INTERNED_STRING_TO_JSID(cx, str);
     875           0 :             if (!whitelist->put(JSID_BITS(id))) {
     876           0 :                 JS_ReportOutOfMemory(cx);
     877           0 :                 return false;
     878             :             }
     879             :         }
     880             :     }
     881             : 
     882           0 :     return true;
     883             : }
     884             : 
     885             : /***************************************************************************/
     886             : 
     887             : // static
     888             : void
     889           0 : XPCWrappedNativeScope::DebugDumpAllScopes(int16_t depth)
     890             : {
     891             : #ifdef DEBUG
     892           0 :     depth-- ;
     893             : 
     894             :     // get scope count.
     895           0 :     int count = 0;
     896             :     XPCWrappedNativeScope* cur;
     897           0 :     for (cur = gScopes; cur; cur = cur->mNext)
     898           0 :         count++ ;
     899             : 
     900           0 :     XPC_LOG_ALWAYS(("chain of %d XPCWrappedNativeScope(s)", count));
     901           0 :     XPC_LOG_INDENT();
     902           0 :         XPC_LOG_ALWAYS(("gDyingScopes @ %p", gDyingScopes));
     903           0 :         if (depth)
     904           0 :             for (cur = gScopes; cur; cur = cur->mNext)
     905           0 :                 cur->DebugDump(depth);
     906           0 :     XPC_LOG_OUTDENT();
     907             : #endif
     908           0 : }
     909             : 
     910             : void
     911           0 : XPCWrappedNativeScope::DebugDump(int16_t depth)
     912             : {
     913             : #ifdef DEBUG
     914           0 :     depth-- ;
     915           0 :     XPC_LOG_ALWAYS(("XPCWrappedNativeScope @ %p", this));
     916           0 :     XPC_LOG_INDENT();
     917           0 :         XPC_LOG_ALWAYS(("mNext @ %p", mNext));
     918           0 :         XPC_LOG_ALWAYS(("mComponents @ %p", mComponents.get()));
     919           0 :         XPC_LOG_ALWAYS(("mGlobalJSObject @ %p", mGlobalJSObject.get()));
     920             : 
     921           0 :         XPC_LOG_ALWAYS(("mWrappedNativeMap @ %p with %d wrappers(s)",
     922             :                         mWrappedNativeMap, mWrappedNativeMap->Count()));
     923             :         // iterate contexts...
     924           0 :         if (depth && mWrappedNativeMap->Count()) {
     925           0 :             XPC_LOG_INDENT();
     926           0 :             for (auto i = mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
     927           0 :                 auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
     928           0 :                 entry->value->DebugDump(depth);
     929             :             }
     930           0 :             XPC_LOG_OUTDENT();
     931             :         }
     932             : 
     933           0 :         XPC_LOG_ALWAYS(("mWrappedNativeProtoMap @ %p with %d protos(s)",
     934             :                         mWrappedNativeProtoMap,
     935             :                         mWrappedNativeProtoMap->Count()));
     936             :         // iterate contexts...
     937           0 :         if (depth && mWrappedNativeProtoMap->Count()) {
     938           0 :             XPC_LOG_INDENT();
     939           0 :             for (auto i = mWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
     940           0 :                 auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get());
     941           0 :                 entry->value->DebugDump(depth);
     942             :             }
     943           0 :             XPC_LOG_OUTDENT();
     944             :         }
     945           0 :     XPC_LOG_OUTDENT();
     946             : #endif
     947           0 : }
     948             : 
     949             : void
     950           0 : XPCWrappedNativeScope::AddSizeOfAllScopesIncludingThis(ScopeSizeInfo* scopeSizeInfo)
     951             : {
     952           0 :     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
     953           0 :         cur->AddSizeOfIncludingThis(scopeSizeInfo);
     954           0 : }
     955             : 
     956             : void
     957           0 : XPCWrappedNativeScope::AddSizeOfIncludingThis(ScopeSizeInfo* scopeSizeInfo)
     958             : {
     959           0 :     scopeSizeInfo->mScopeAndMapSize += scopeSizeInfo->mMallocSizeOf(this);
     960           0 :     scopeSizeInfo->mScopeAndMapSize +=
     961           0 :         mWrappedNativeMap->SizeOfIncludingThis(scopeSizeInfo->mMallocSizeOf);
     962           0 :     scopeSizeInfo->mScopeAndMapSize +=
     963           0 :         mWrappedNativeProtoMap->SizeOfIncludingThis(scopeSizeInfo->mMallocSizeOf);
     964             : 
     965           0 :     if (dom::HasProtoAndIfaceCache(mGlobalJSObject)) {
     966           0 :         dom::ProtoAndIfaceCache* cache = dom::GetProtoAndIfaceCache(mGlobalJSObject);
     967           0 :         scopeSizeInfo->mProtoAndIfaceCacheSize +=
     968           0 :             cache->SizeOfIncludingThis(scopeSizeInfo->mMallocSizeOf);
     969             :     }
     970             : 
     971             :     // There are other XPCWrappedNativeScope members that could be measured;
     972             :     // the above ones have been seen by DMD to be worth measuring.  More stuff
     973             :     // may be added later.
     974           0 : }

Generated by: LCOV version 1.13