tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WindowDestroyedEvent.cpp (5253B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 #include "WindowDestroyedEvent.h"
      8 
      9 #include "js/Wrapper.h"
     10 #include "jsapi.h"
     11 #include "mozilla/AppShutdown.h"
     12 #include "mozilla/BasePrincipal.h"
     13 #include "mozilla/Components.h"
     14 #include "mozilla/ProfilerLabels.h"
     15 #include "nsCOMPtr.h"
     16 #include "nsContentUtils.h"
     17 #include "nsFocusManager.h"
     18 #include "nsGlobalWindowInner.h"
     19 #include "nsGlobalWindowOuter.h"
     20 #include "nsIAppStartup.h"
     21 #include "nsIPrincipal.h"
     22 #include "nsISupportsPrimitives.h"
     23 #include "nsJSPrincipals.h"
     24 #include "nsJSUtils.h"
     25 #include "xpcpublic.h"
     26 
     27 namespace mozilla {
     28 
     29 struct BrowserCompartmentMatcher : public js::CompartmentFilter {
     30  bool match(JS::Compartment* aC) const override {
     31    return !xpc::MightBeWebContentCompartment(aC);
     32  }
     33 };
     34 
     35 WindowDestroyedEvent::WindowDestroyedEvent(nsGlobalWindowInner* aWindow,
     36                                           uint64_t aID, const char* aTopic)
     37    : mozilla::Runnable("WindowDestroyedEvent"),
     38      mID(aID),
     39      mPhase(Phase::Destroying),
     40      mTopic(aTopic),
     41      mIsInnerWindow(true) {
     42  mWindow = do_GetWeakReference(aWindow);
     43 }
     44 
     45 WindowDestroyedEvent::WindowDestroyedEvent(nsGlobalWindowOuter* aWindow,
     46                                           uint64_t aID, const char* aTopic)
     47    : mozilla::Runnable("WindowDestroyedEvent"),
     48      mID(aID),
     49      mPhase(Phase::Destroying),
     50      mTopic(aTopic),
     51      mIsInnerWindow(false) {
     52  mWindow = do_GetWeakReference(aWindow);
     53 }
     54 
     55 NS_IMETHODIMP
     56 WindowDestroyedEvent::Run() {
     57  AUTO_PROFILER_LABEL("WindowDestroyedEvent::Run", OTHER);
     58 
     59  nsCOMPtr<nsPIDOMWindowOuter> nukedOuter;
     60 
     61  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
     62  if (!observerService) {
     63    return NS_OK;
     64  }
     65 
     66  nsCOMPtr<nsISupportsPRUint64> wrapper =
     67      do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
     68  if (wrapper) {
     69    wrapper->SetData(mID);
     70    observerService->NotifyObservers(wrapper, mTopic.get(), nullptr);
     71  }
     72 
     73  switch (mPhase) {
     74    case Phase::Destroying: {
     75      bool skipNukeCrossCompartment = false;
     76 #ifndef DEBUG
     77      skipNukeCrossCompartment =
     78          AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed);
     79 #endif
     80 
     81      if (!skipNukeCrossCompartment) {
     82        // The compartment nuking phase might be too expensive, so do that
     83        // part off of idle dispatch.
     84 
     85        // For the compartment nuking phase, we dispatch either an
     86        // inner-window-nuked or an outer-window-nuked notification.
     87        // This will allow tests to wait for compartment nuking to happen.
     88        if (mTopic.EqualsLiteral("inner-window-destroyed")) {
     89          mTopic.AssignLiteral("inner-window-nuked");
     90        } else if (mTopic.EqualsLiteral("outer-window-destroyed")) {
     91          mTopic.AssignLiteral("outer-window-nuked");
     92        }
     93        mPhase = Phase::Nuking;
     94 
     95        nsCOMPtr<nsIRunnable> copy(this);
     96        NS_DispatchToCurrentThreadQueue(copy.forget(), 1000,
     97                                        EventQueuePriority::Idle);
     98      }
     99    } break;
    100 
    101    case Phase::Nuking: {
    102      nsCOMPtr<nsISupports> window = do_QueryReferent(mWindow);
    103      if (window) {
    104        nsGlobalWindowInner* currentInner;
    105        if (mIsInnerWindow) {
    106          currentInner = nsGlobalWindowInner::FromSupports(window);
    107        } else {
    108          nsGlobalWindowOuter* outer =
    109              nsGlobalWindowOuter::FromSupports(window);
    110          currentInner =
    111              nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow());
    112          nukedOuter = outer;
    113        }
    114        NS_ENSURE_TRUE(currentInner, NS_OK);
    115 
    116        dom::AutoJSAPI jsapi;
    117        jsapi.Init();
    118        JSContext* cx = jsapi.cx();
    119        JS::Rooted<JSObject*> obj(cx, currentInner->GetGlobalJSObject());
    120        if (obj && !js::IsSystemRealm(js::GetNonCCWObjectRealm(obj))) {
    121          JS::Realm* realm = js::GetNonCCWObjectRealm(obj);
    122 
    123          xpc::NukeJSStackFrames(realm);
    124 
    125          nsCOMPtr<nsIPrincipal> pc =
    126              nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
    127 
    128          if (BasePrincipal::Cast(pc)->AddonPolicy()) {
    129            // We want to nuke all references to the add-on realm.
    130            xpc::NukeAllWrappersForRealm(cx, realm,
    131                                         mIsInnerWindow
    132                                             ? js::DontNukeWindowReferences
    133                                             : js::NukeWindowReferences);
    134          } else {
    135            // We only want to nuke wrappers for the chrome->content case
    136            js::NukeCrossCompartmentWrappers(
    137                cx, BrowserCompartmentMatcher(), realm,
    138                mIsInnerWindow ? js::DontNukeWindowReferences
    139                               : js::NukeWindowReferences,
    140                js::NukeIncomingReferences);
    141          }
    142        }
    143      }
    144    } break;
    145  }
    146 
    147  if (nukedOuter) {
    148    nsFocusManager* fm = nsFocusManager::GetFocusManager();
    149    if (fm) {
    150      fm->WasNuked(nukedOuter);
    151    }
    152  }
    153 
    154  return NS_OK;
    155 }
    156 
    157 }  // namespace mozilla