tor-browser

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

nsXPConnect.cpp (38073B)


      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 /* High level class and public functions implementation. */
      8 
      9 #include "js/Transcoding.h"
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/Base64.h"
     12 #include "mozilla/Likely.h"
     13 
     14 #include "XPCWrapper.h"
     15 #include "jsfriendapi.h"
     16 #include "js/AllocationLogging.h"  // JS::SetLogCtorDtorFunctions
     17 #include "js/CompileOptions.h"     // JS::ReadOnlyCompileOptions
     18 #include "js/Object.h"             // JS::GetClass
     19 #include "js/ProfilingStack.h"
     20 #include "GeckoProfiler.h"
     21 #include "mozJSModuleLoader.h"
     22 #include "nsJSEnvironment.h"
     23 #include "nsThreadUtils.h"
     24 #include "nsDOMJSUtils.h"
     25 
     26 #include "WrapperFactory.h"
     27 #include "AccessCheck.h"
     28 #include "JSServices.h"
     29 
     30 #include "mozilla/BasePrincipal.h"
     31 #include "mozilla/dom/BindingUtils.h"
     32 #include "mozilla/dom/DOMException.h"
     33 #include "mozilla/dom/Exceptions.h"
     34 #include "mozilla/dom/Promise.h"
     35 #include "mozilla/glean/bindings/Glean.h"
     36 #include "mozilla/glean/bindings/GleanPings.h"
     37 #include "mozilla/ScriptPreloader.h"
     38 
     39 #include "nsDOMMutationObserver.h"
     40 #include "nsICycleCollectorListener.h"
     41 #include "nsCycleCollector.h"
     42 #include "nsIOService.h"
     43 #include "nsIObjectInputStream.h"
     44 #include "nsIObjectOutputStream.h"
     45 #include "nsScriptSecurityManager.h"
     46 #include "nsContentUtils.h"
     47 #include "nsScriptError.h"
     48 #include "nsJSUtils.h"
     49 #include "nsRFPService.h"
     50 #include "prsystem.h"
     51 
     52 #include "xpcprivate.h"
     53 
     54 #ifdef XP_WIN
     55 #  include "mozilla/WinHeaderOnlyUtils.h"
     56 #else
     57 #  include <sys/mman.h>
     58 #endif
     59 
     60 using namespace mozilla;
     61 using namespace mozilla::dom;
     62 using namespace xpc;
     63 using namespace JS;
     64 
     65 NS_IMPL_ISUPPORTS(nsXPConnect, nsIXPConnect)
     66 
     67 nsXPConnect* nsXPConnect::gSelf = nullptr;
     68 bool nsXPConnect::gOnceAliveNowDead = false;
     69 
     70 // Global cache of the default script security manager (QI'd to
     71 // nsIScriptSecurityManager) and the system principal.
     72 nsIScriptSecurityManager* nsXPConnect::gScriptSecurityManager = nullptr;
     73 nsIPrincipal* nsXPConnect::gSystemPrincipal = nullptr;
     74 
     75 const char XPC_EXCEPTION_CONTRACTID[] = "@mozilla.org/js/xpc/Exception;1";
     76 const char XPC_CONSOLE_CONTRACTID[] = "@mozilla.org/consoleservice;1";
     77 const char XPC_SCRIPT_ERROR_CONTRACTID[] = "@mozilla.org/scripterror;1";
     78 
     79 /***************************************************************************/
     80 
     81 nsXPConnect::nsXPConnect() {
     82 #ifdef MOZ_GECKO_PROFILER
     83  JS::SetProfilingThreadCallbacks(profiler_register_thread,
     84                                  profiler_unregister_thread);
     85 #endif
     86 }
     87 
     88 // static
     89 void nsXPConnect::InitJSContext() {
     90  MOZ_ASSERT(!gSelf->mContext);
     91 
     92  XPCJSContext* xpccx = XPCJSContext::NewXPCJSContext();
     93  if (!xpccx) {
     94    MOZ_CRASH("Couldn't create XPCJSContext.");
     95  }
     96  gSelf->mContext = xpccx;
     97  gSelf->mRuntime = xpccx->Runtime();
     98 
     99  mozJSModuleLoader::InitStatics();
    100 
    101  // Initialize the script preloader cache.
    102  (void)mozilla::ScriptPreloader::GetSingleton();
    103 
    104  nsJSContext::EnsureStatics();
    105 }
    106 
    107 void xpc::InitializeJSContext() { nsXPConnect::InitJSContext(); }
    108 
    109 nsXPConnect::~nsXPConnect() {
    110  MOZ_ASSERT(mRuntime);
    111 
    112  mRuntime->DeleteSingletonScopes();
    113 
    114  // In order to clean up everything properly, we need to GC twice: once now,
    115  // to clean anything that can go away on its own (like the Junk Scope, which
    116  // we unrooted above), and once after forcing a bunch of shutdown in
    117  // XPConnect, to clean the stuff we forcibly disconnected. The forced
    118  // shutdown code defaults to leaking in a number of situations, so we can't
    119  // get by with only the second GC. :-(
    120  //
    121  // Bug 1650075: These should really pass GCOptions::Shutdown but doing that
    122  // seems to cause crashes.
    123  mRuntime->GarbageCollect(JS::GCOptions::Normal,
    124                           JS::GCReason::XPCONNECT_SHUTDOWN);
    125 
    126  XPCWrappedNativeScope::SystemIsBeingShutDown();
    127 
    128  // The above causes us to clean up a bunch of XPConnect data structures,
    129  // after which point we need to GC to clean everything up. We need to do
    130  // this before deleting the XPCJSContext, because doing so destroys the
    131  // maps that our finalize callback depends on.
    132  mRuntime->GarbageCollect(JS::GCOptions::Normal,
    133                           JS::GCReason::XPCONNECT_SHUTDOWN);
    134 
    135  NS_RELEASE(gSystemPrincipal);
    136  gScriptSecurityManager = nullptr;
    137 
    138  // shutdown the logging system
    139  XPC_LOG_FINISH();
    140 
    141  delete mContext;
    142 
    143  MOZ_ASSERT(gSelf == this);
    144  gSelf = nullptr;
    145  gOnceAliveNowDead = true;
    146 }
    147 
    148 // static
    149 void nsXPConnect::InitStatics() {
    150 #ifdef NS_BUILD_REFCNT_LOGGING
    151  // These functions are used for reporting leaks, so we register them as early
    152  // as possible to avoid missing any classes' creations.
    153  JS::SetLogCtorDtorFunctions(NS_LogCtor, NS_LogDtor);
    154 #endif
    155 
    156  gSelf = new nsXPConnect();
    157  gOnceAliveNowDead = false;
    158 
    159  // Initial extra ref to keep the singleton alive
    160  // balanced by explicit call to ReleaseXPConnectSingleton()
    161  NS_ADDREF(gSelf);
    162 
    163  // Fire up the SSM.
    164  nsScriptSecurityManager::InitStatics();
    165  gScriptSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager();
    166  gScriptSecurityManager->GetSystemPrincipal(&gSystemPrincipal);
    167  MOZ_RELEASE_ASSERT(gSystemPrincipal);
    168 }
    169 
    170 // static
    171 void nsXPConnect::ReleaseXPConnectSingleton() {
    172  nsXPConnect* xpc = gSelf;
    173  if (xpc) {
    174    nsrefcnt cnt;
    175    NS_RELEASE2(xpc, cnt);
    176  }
    177 
    178  mozJSModuleLoader::ShutdownLoaders();
    179 }
    180 
    181 // static
    182 XPCJSRuntime* nsXPConnect::GetRuntimeInstance() {
    183  MOZ_RELEASE_ASSERT(NS_IsMainThread());
    184  return gSelf->mRuntime;
    185 }
    186 
    187 void xpc::ErrorBase::Init(JSErrorBase* aReport) {
    188  if (!aReport->filename) {
    189    mFileName.SetIsVoid(true);
    190  } else {
    191    mFileName.Assign(aReport->filename.c_str());
    192  }
    193 
    194  mSourceId = aReport->sourceId;
    195  mLineNumber = aReport->lineno;
    196  mColumn = aReport->column.oneOriginValue();
    197 }
    198 
    199 void xpc::ErrorNote::Init(JSErrorNotes::Note* aNote) {
    200  xpc::ErrorBase::Init(aNote);
    201 
    202  ErrorNoteToMessageString(aNote, mErrorMsg);
    203 }
    204 
    205 void xpc::ErrorReport::Init(JSErrorReport* aReport, const char* aToStringResult,
    206                            bool aIsChrome, uint64_t aWindowID) {
    207  xpc::ErrorBase::Init(aReport);
    208  mCategory = aIsChrome ? "chrome javascript"_ns : "content javascript"_ns;
    209  mWindowID = aWindowID;
    210 
    211  if (aToStringResult) {
    212    AppendUTF8toUTF16(mozilla::MakeStringSpan(aToStringResult), mErrorMsg);
    213  }
    214  if (mErrorMsg.IsEmpty()) {
    215    ErrorReportToMessageString(aReport, mErrorMsg);
    216  }
    217  if (mErrorMsg.IsEmpty()) {
    218    mErrorMsg.AssignLiteral("<unknown>");
    219  }
    220 
    221  if (aReport->errorMessageName) {
    222    mErrorMsgName.AssignASCII(aReport->errorMessageName);
    223  } else {
    224    mErrorMsgName.Truncate();
    225  }
    226 
    227  mIsWarning = aReport->isWarning();
    228  mIsMuted = aReport->isMuted;
    229 
    230  if (aReport->notes) {
    231    if (!mNotes.SetLength(aReport->notes->length(), fallible)) {
    232      return;
    233    }
    234 
    235    size_t i = 0;
    236    for (auto&& note : *aReport->notes) {
    237      mNotes.ElementAt(i).Init(note.get());
    238      i++;
    239    }
    240  }
    241 }
    242 
    243 void xpc::ErrorReport::Init(JSContext* aCx, mozilla::dom::Exception* aException,
    244                            bool aIsChrome, uint64_t aWindowID) {
    245  mCategory = aIsChrome ? "chrome javascript"_ns : "content javascript"_ns;
    246  mWindowID = aWindowID;
    247 
    248  aException->GetErrorMessage(mErrorMsg);
    249 
    250  aException->GetFilename(aCx, mFileName);
    251  if (mFileName.IsEmpty()) {
    252    mFileName.SetIsVoid(true);
    253  }
    254  mSourceId = aException->SourceId(aCx);
    255  mLineNumber = aException->LineNumber(aCx);
    256  mColumn = aException->ColumnNumber(aCx);
    257 }
    258 
    259 static LazyLogModule gJSDiagnostics("JSDiagnostics");
    260 
    261 void xpc::ErrorBase::AppendErrorDetailsTo(nsCString& error) {
    262  error.Append(mFileName);
    263  error.AppendLiteral(", line ");
    264  error.AppendInt(mLineNumber, 10);
    265  error.AppendLiteral(": ");
    266  AppendUTF16toUTF8(mErrorMsg, error);
    267 }
    268 
    269 void xpc::ErrorNote::LogToStderr() {
    270  if (!nsJSUtils::DumpEnabled()) {
    271    return;
    272  }
    273 
    274  nsAutoCString error;
    275  error.AssignLiteral("JavaScript note: ");
    276  AppendErrorDetailsTo(error);
    277 
    278  fprintf(stderr, "%s\n", error.get());
    279  fflush(stderr);
    280 }
    281 
    282 void xpc::ErrorReport::LogToStderr() {
    283  if (!nsJSUtils::DumpEnabled()) {
    284    return;
    285  }
    286 
    287  nsAutoCString error;
    288  error.AssignLiteral("JavaScript ");
    289  if (IsWarning()) {
    290    error.AppendLiteral("warning: ");
    291  } else {
    292    error.AppendLiteral("error: ");
    293  }
    294  AppendErrorDetailsTo(error);
    295 
    296  fprintf(stderr, "%s\n", error.get());
    297  fflush(stderr);
    298 
    299  for (size_t i = 0, len = mNotes.Length(); i < len; i++) {
    300    ErrorNote& note = mNotes[i];
    301    note.LogToStderr();
    302  }
    303 }
    304 
    305 void xpc::ErrorReport::LogToConsole() {
    306  LogToConsoleWithStack(nullptr, JS::NothingHandleValue, nullptr, nullptr);
    307 }
    308 
    309 void xpc::ErrorReport::LogToConsoleWithStack(
    310    nsGlobalWindowInner* aWin, JS::Handle<mozilla::Maybe<JS::Value>> aException,
    311    JS::HandleObject aStack, JS::HandleObject aStackGlobal) {
    312  if (aStack) {
    313    MOZ_ASSERT(aStackGlobal);
    314    MOZ_ASSERT(JS_IsGlobalObject(aStackGlobal));
    315    js::AssertSameCompartment(aStack, aStackGlobal);
    316  } else {
    317    MOZ_ASSERT(!aStackGlobal);
    318  }
    319 
    320  LogToStderr();
    321 
    322  MOZ_LOG(gJSDiagnostics, IsWarning() ? LogLevel::Warning : LogLevel::Error,
    323          ("file %s, line %u\n%s", mFileName.get(), mLineNumber,
    324           NS_ConvertUTF16toUTF8(mErrorMsg).get()));
    325 
    326  // Log to the console. We do this last so that we can simply return if
    327  // there's no console service without affecting the other reporting
    328  // mechanisms.
    329  nsCOMPtr<nsIConsoleService> consoleService =
    330      do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    331  NS_ENSURE_TRUE_VOID(consoleService);
    332 
    333  RefPtr<nsScriptErrorBase> errorObject =
    334      CreateScriptError(aWin, aException, aStack, aStackGlobal);
    335  errorObject->SetErrorMessageName(mErrorMsgName);
    336 
    337  uint32_t flags =
    338      mIsWarning ? nsIScriptError::warningFlag : nsIScriptError::errorFlag;
    339  nsresult rv = errorObject->InitWithWindowID(
    340      mErrorMsg, mFileName, mLineNumber, mColumn, flags, mCategory, mWindowID,
    341      mCategory.Equals("chrome javascript"_ns));
    342  NS_ENSURE_SUCCESS_VOID(rv);
    343 
    344  rv = errorObject->InitSourceId(mSourceId);
    345  NS_ENSURE_SUCCESS_VOID(rv);
    346 
    347  rv = errorObject->InitIsPromiseRejection(mIsPromiseRejection);
    348  NS_ENSURE_SUCCESS_VOID(rv);
    349 
    350  for (size_t i = 0, len = mNotes.Length(); i < len; i++) {
    351    ErrorNote& note = mNotes[i];
    352 
    353    nsScriptErrorNote* noteObject = new nsScriptErrorNote();
    354    noteObject->Init(note.mErrorMsg, note.mFileName, note.mSourceId,
    355                     note.mLineNumber, note.mColumn);
    356    errorObject->AddNote(noteObject);
    357  }
    358 
    359  consoleService->LogMessage(errorObject);
    360 }
    361 
    362 /* static */
    363 void xpc::ErrorNote::ErrorNoteToMessageString(JSErrorNotes::Note* aNote,
    364                                              nsAString& aString) {
    365  aString.Truncate();
    366  if (aNote->message()) {
    367    aString.Append(NS_ConvertUTF8toUTF16(aNote->message().c_str()));
    368  }
    369 }
    370 
    371 /* static */
    372 void xpc::ErrorReport::ErrorReportToMessageString(JSErrorReport* aReport,
    373                                                  nsAString& aString) {
    374  aString.Truncate();
    375  if (aReport->message()) {
    376    // Don't prefix warnings with an often misleading name like "Error: ".
    377    if (!aReport->isWarning()) {
    378      JSLinearString* name = js::GetErrorTypeName(
    379          CycleCollectedJSContext::Get()->Context(), aReport->exnType);
    380      if (name) {
    381        AssignJSLinearString(aString, name);
    382        aString.AppendLiteral(": ");
    383      }
    384    }
    385    aString.Append(NS_ConvertUTF8toUTF16(aReport->message().c_str()));
    386  }
    387 }
    388 
    389 /***************************************************************************/
    390 
    391 void xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS) {
    392  // QIing to nsIXPConnectWrappedJSUnmarkGray may have side effects!
    393  nsCOMPtr<nsIXPConnectWrappedJSUnmarkGray> wjsug =
    394      do_QueryInterface(aWrappedJS);
    395  (void)wjsug;
    396  MOZ_ASSERT(!wjsug,
    397             "One should never be able to QI to "
    398             "nsIXPConnectWrappedJSUnmarkGray successfully!");
    399 }
    400 
    401 /***************************************************************************/
    402 /***************************************************************************/
    403 // nsIXPConnect interface methods...
    404 
    405 template <typename T>
    406 static inline T UnexpectedFailure(T rv) {
    407  NS_ERROR("This is not supposed to fail!");
    408  return rv;
    409 }
    410 
    411 void xpc::TraceXPCGlobal(JSTracer* trc, JSObject* obj) {
    412  if (JS::GetClass(obj)->flags & JSCLASS_DOM_GLOBAL) {
    413    mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
    414  }
    415 
    416  // We might be called from a GC during the creation of a global, before we've
    417  // been able to set up the compartment private.
    418  if (xpc::CompartmentPrivate* priv = xpc::CompartmentPrivate::Get(obj)) {
    419    MOZ_ASSERT(priv->GetScope());
    420    priv->GetScope()->TraceInside(trc);
    421  }
    422 }
    423 
    424 namespace xpc {
    425 
    426 JSObject* CreateGlobalObject(JSContext* cx, const JSClass* clasp,
    427                             nsIPrincipal* principal,
    428                             JS::RealmOptions& aOptions) {
    429  MOZ_ASSERT(NS_IsMainThread(), "using a principal off the main thread?");
    430  MOZ_ASSERT(principal);
    431 
    432  MOZ_RELEASE_ASSERT(
    433      principal != nsContentUtils::GetNullSubjectPrincipal(),
    434      "The null subject principal is getting inherited - fix that!");
    435 
    436  RootedObject global(cx);
    437  {
    438    SiteIdentifier site;
    439    nsresult rv = BasePrincipal::Cast(principal)->GetSiteIdentifier(site);
    440    NS_ENSURE_SUCCESS(rv, nullptr);
    441 
    442    global = JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal),
    443                                JS::DontFireOnNewGlobalHook, aOptions);
    444    if (!global) {
    445      return nullptr;
    446    }
    447    JSAutoRealm ar(cx, global);
    448 
    449    RealmPrivate::Init(global, site);
    450 
    451    if (clasp->flags & JSCLASS_DOM_GLOBAL) {
    452 #ifdef DEBUG
    453      // Verify that the right trace hook is called. Note that this doesn't
    454      // work right for wrapped globals, since the tracing situation there is
    455      // more complicated. Manual inspection shows that they do the right
    456      // thing. Also note that we only check this for JSCLASS_DOM_GLOBAL
    457      // classes because xpc::TraceXPCGlobal won't call TraceProtoAndIfaceCache
    458      // unless that flag is set.
    459      if (!((const JSClass*)clasp)->isWrappedNative()) {
    460        VerifyTraceProtoAndIfaceCacheCalledTracer trc(cx);
    461        TraceChildren(&trc, GCCellPtr(global.get()));
    462        MOZ_ASSERT(trc.ok,
    463                   "Trace hook on global needs to call TraceXPCGlobal for "
    464                   "XPConnect compartments.");
    465      }
    466 #endif
    467 
    468      const char* className = clasp->name;
    469      AllocateProtoAndIfaceCache(global,
    470                                 (strcmp(className, "Window") == 0 ||
    471                                  strcmp(className, "ChromeWindow") == 0)
    472                                     ? ProtoAndIfaceCache::WindowLike
    473                                     : ProtoAndIfaceCache::NonWindowLike);
    474    }
    475  }
    476 
    477  return global;
    478 }
    479 
    480 void InitGlobalObjectOptions(JS::RealmOptions& aOptions,
    481                             bool aIsSystemPrincipal, bool aSecureContext,
    482                             bool aForceUTC, bool aAlwaysUseFdlibm,
    483                             bool aLocaleEnUS,
    484                             const nsACString& aLanguageOverride,
    485                             const nsAString& aTimezoneOverride) {
    486  if (aIsSystemPrincipal) {
    487    // Make toSource functions [ChromeOnly]
    488    aOptions.creationOptions().setToSourceEnabled(true);
    489    // Make sure [SecureContext] APIs are visible:
    490    aOptions.creationOptions().setSecureContext(true);
    491    aOptions.behaviors().setClampAndJitterTime(false);
    492    aOptions.behaviors().setDiscardSource(ShouldDiscardSystemSource());
    493    MOZ_ASSERT(aSecureContext,
    494               "aIsSystemPrincipal should imply aSecureContext");
    495  } else {
    496    aOptions.creationOptions().setSecureContext(aSecureContext);
    497  }
    498 
    499  if (aForceUTC) {
    500    nsCString timeZone = nsRFPService::GetSpoofedJSTimeZone();
    501    aOptions.behaviors().setTimeZoneOverride(timeZone.get());
    502  } else if (!aTimezoneOverride.IsEmpty()) {
    503    aOptions.behaviors().setTimeZoneOverride(
    504        NS_ConvertUTF16toUTF8(aTimezoneOverride).get());
    505  }
    506  aOptions.creationOptions().setAlwaysUseFdlibm(aAlwaysUseFdlibm);
    507  if (aLocaleEnUS) {
    508    nsCString locale = nsRFPService::GetSpoofedJSLocale();
    509    aOptions.behaviors().setLocaleOverride(locale.get());
    510  } else if (!aLanguageOverride.IsEmpty()) {
    511    aOptions.behaviors().setLocaleOverride(
    512        PromiseFlatCString(aLanguageOverride).get());
    513  }
    514 }
    515 
    516 bool InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal,
    517                      uint32_t aFlags) {
    518  // Immediately enter the global's realm so that everything we create
    519  // ends up there.
    520  JSAutoRealm ar(aJSContext, aGlobal);
    521 
    522  // Stuff coming through this path always ends up as a DOM global.
    523  MOZ_ASSERT(JS::GetClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL);
    524 
    525  if (!(aFlags & xpc::OMIT_COMPONENTS_OBJECT)) {
    526    // XPCCallContext gives us an active request needed to save/restore.
    527    if (!ObjectScope(aGlobal)->AttachComponentsObject(aJSContext) ||
    528        !XPCNativeWrapper::AttachNewConstructorObject(aJSContext, aGlobal)) {
    529      return UnexpectedFailure(false);
    530    }
    531 
    532    if (!mozJSModuleLoader::Get()->DefineJSServices(aJSContext, aGlobal)) {
    533      return UnexpectedFailure(false);
    534    }
    535  }
    536 
    537  if (!(aFlags & xpc::DONT_FIRE_ONNEWGLOBALHOOK)) {
    538    JS_FireOnNewGlobalObject(aJSContext, aGlobal);
    539  }
    540 
    541  return true;
    542 }
    543 
    544 nsresult InitClassesWithNewWrappedGlobal(JSContext* aJSContext,
    545                                         nsISupports* aCOMObj,
    546                                         nsIPrincipal* aPrincipal,
    547                                         uint32_t aFlags,
    548                                         JS::RealmOptions& aOptions,
    549                                         MutableHandleObject aNewGlobal) {
    550  MOZ_ASSERT(aJSContext, "bad param");
    551  MOZ_ASSERT(aCOMObj, "bad param");
    552 
    553  // We pass null for the 'extra' pointer during global object creation, so
    554  // we need to have a principal.
    555  MOZ_ASSERT(aPrincipal);
    556  // All uses (at time of writing) were System Principal, meaning
    557  // aShouldResistFingerprinting can be hardcoded to false.
    558  // If this changes, ShouldRFP needs to be updated accordingly.
    559  MOZ_RELEASE_ASSERT(aPrincipal->IsSystemPrincipal());
    560 
    561  // Similarly we can thus hardcode the RTPCallerType.
    562  aOptions.behaviors().setReduceTimerPrecisionCallerType(
    563      RTPCallerTypeToToken(RTPCallerType::SystemPrincipal));
    564 
    565  InitGlobalObjectOptions(aOptions, /* aSystemPrincipal */ true,
    566                          /* aSecureContext */ true,
    567                          /* aForceUTC */ false, /* aAlwaysUseFdlibm */ false,
    568                          /* aLocaleEnUS */ false,
    569                          /* aLanguageOverride */ ""_ns,
    570                          /* aTimezoneOverride */ u""_ns);
    571 
    572  // Call into XPCWrappedNative to make a new global object, scope, and global
    573  // prototype.
    574  xpcObjectHelper helper(aCOMObj);
    575  MOZ_ASSERT(helper.GetScriptableFlags() & XPC_SCRIPTABLE_IS_GLOBAL_OBJECT);
    576  RefPtr<XPCWrappedNative> wrappedGlobal;
    577  nsresult rv = XPCWrappedNative::WrapNewGlobal(
    578      aJSContext, helper, aPrincipal, aOptions, getter_AddRefs(wrappedGlobal));
    579  NS_ENSURE_SUCCESS(rv, rv);
    580 
    581  // Grab a copy of the global and enter its compartment.
    582  RootedObject global(aJSContext, wrappedGlobal->GetFlatJSObject());
    583  MOZ_ASSERT(JS_IsGlobalObject(global));
    584 
    585  if (!InitGlobalObject(aJSContext, global, aFlags)) {
    586    return UnexpectedFailure(NS_ERROR_FAILURE);
    587  }
    588 
    589  {  // Scope for JSAutoRealm
    590    JSAutoRealm ar(aJSContext, global);
    591    if (!JS_DefineProfilingFunctions(aJSContext, global)) {
    592      return UnexpectedFailure(NS_ERROR_OUT_OF_MEMORY);
    593    }
    594    if (aPrincipal->IsSystemPrincipal()) {
    595      if (!glean::Glean::DefineGlean(aJSContext, global) ||
    596          !glean::GleanPings::DefineGleanPings(aJSContext, global)) {
    597        return UnexpectedFailure(NS_ERROR_FAILURE);
    598      }
    599    }
    600  }
    601 
    602  aNewGlobal.set(global);
    603  return NS_OK;
    604 }
    605 
    606 nsCString GetFunctionName(JSContext* cx, HandleObject obj) {
    607  RootedObject inner(cx, js::UncheckedUnwrap(obj));
    608  JSAutoRealm ar(cx, inner);
    609 
    610  RootedFunction fun(cx, JS_GetObjectFunction(inner));
    611  if (!fun) {
    612    // If the object isn't a function, it's likely that it has a single
    613    // function property (for things like nsITimerCallback). In this case,
    614    // return the name of that function property.
    615 
    616    Rooted<IdVector> idArray(cx, IdVector(cx));
    617    if (!JS_Enumerate(cx, inner, &idArray)) {
    618      JS_ClearPendingException(cx);
    619      return nsCString("error");
    620    }
    621 
    622    if (idArray.length() != 1) {
    623      return nsCString("nonfunction");
    624    }
    625 
    626    RootedId id(cx, idArray[0]);
    627    RootedValue v(cx);
    628    if (!JS_GetPropertyById(cx, inner, id, &v)) {
    629      JS_ClearPendingException(cx);
    630      return nsCString("nonfunction");
    631    }
    632 
    633    if (!v.isObject()) {
    634      return nsCString("nonfunction");
    635    }
    636 
    637    RootedObject vobj(cx, &v.toObject());
    638    return GetFunctionName(cx, vobj);
    639  }
    640 
    641  RootedString funName(cx, JS_GetMaybePartialFunctionDisplayId(fun));
    642  RootedScript script(cx, JS_GetFunctionScript(cx, fun));
    643  const char* filename = script ? JS_GetScriptFilename(script) : "anonymous";
    644  const char* filenameSuffix = strrchr(filename, '/');
    645 
    646  if (filenameSuffix) {
    647    filenameSuffix++;
    648  } else {
    649    filenameSuffix = filename;
    650  }
    651 
    652  nsCString displayName("anonymous");
    653  if (funName) {
    654    RootedValue funNameVal(cx, StringValue(funName));
    655    if (!XPCConvert::JSData2Native(cx, &displayName, funNameVal,
    656                                   {nsXPTType::T_UTF8STRING}, nullptr, 0,
    657                                   nullptr)) {
    658      JS_ClearPendingException(cx);
    659      return nsCString("anonymous");
    660    }
    661  }
    662 
    663  displayName.Append('[');
    664  displayName.Append(filenameSuffix, strlen(filenameSuffix));
    665  displayName.Append(']');
    666  return displayName;
    667 }
    668 
    669 }  // namespace xpc
    670 
    671 static nsresult NativeInterface2JSObject(JSContext* aCx, HandleObject aScope,
    672                                         nsISupports* aCOMObj,
    673                                         nsWrapperCache* aCache,
    674                                         const nsIID* aIID, bool aAllowWrapping,
    675                                         MutableHandleValue aVal) {
    676  JSAutoRealm ar(aCx, aScope);
    677 
    678  nsresult rv;
    679  xpcObjectHelper helper(aCOMObj, aCache);
    680  if (!XPCConvert::NativeInterface2JSObject(aCx, aVal, helper, aIID,
    681                                            aAllowWrapping, &rv)) {
    682    return rv;
    683  }
    684 
    685  MOZ_ASSERT(
    686      aAllowWrapping || !xpc::WrapperFactory::IsXrayWrapper(&aVal.toObject()),
    687      "Shouldn't be returning a xray wrapper here");
    688 
    689  return NS_OK;
    690 }
    691 
    692 nsresult nsIXPConnect::WrapNative(JSContext* aJSContext, JSObject* aScopeArg,
    693                                  nsISupports* aCOMObj, const nsIID& aIID,
    694                                  JSObject** aRetVal) {
    695  MOZ_ASSERT(aJSContext, "bad param");
    696  MOZ_ASSERT(aScopeArg, "bad param");
    697  MOZ_ASSERT(aCOMObj, "bad param");
    698 
    699  RootedObject aScope(aJSContext, aScopeArg);
    700  RootedValue v(aJSContext);
    701  nsresult rv = NativeInterface2JSObject(aJSContext, aScope, aCOMObj, nullptr,
    702                                         &aIID, true, &v);
    703  if (NS_FAILED(rv)) {
    704    return rv;
    705  }
    706 
    707  if (!v.isObjectOrNull()) {
    708    return NS_ERROR_FAILURE;
    709  }
    710 
    711  *aRetVal = v.toObjectOrNull();
    712  return NS_OK;
    713 }
    714 
    715 nsresult nsIXPConnect::WrapNativeToJSVal(JSContext* aJSContext,
    716                                         JSObject* aScopeArg,
    717                                         nsISupports* aCOMObj,
    718                                         nsWrapperCache* aCache,
    719                                         const nsIID* aIID, bool aAllowWrapping,
    720                                         MutableHandleValue aVal) {
    721  MOZ_ASSERT(aJSContext, "bad param");
    722  MOZ_ASSERT(aScopeArg, "bad param");
    723  MOZ_ASSERT(aCOMObj, "bad param");
    724 
    725  RootedObject aScope(aJSContext, aScopeArg);
    726  return NativeInterface2JSObject(aJSContext, aScope, aCOMObj, aCache, aIID,
    727                                  aAllowWrapping, aVal);
    728 }
    729 
    730 nsresult nsIXPConnect::WrapJS(JSContext* aJSContext, JSObject* aJSObjArg,
    731                              const nsIID& aIID, void** result) {
    732  MOZ_ASSERT(aJSContext, "bad param");
    733  MOZ_ASSERT(aJSObjArg, "bad param");
    734  MOZ_ASSERT(result, "bad param");
    735 
    736  *result = nullptr;
    737 
    738  RootedObject aJSObj(aJSContext, aJSObjArg);
    739 
    740  nsresult rv = NS_ERROR_UNEXPECTED;
    741  if (!XPCConvert::JSObject2NativeInterface(aJSContext, result, aJSObj, &aIID,
    742                                            nullptr, &rv))
    743    return rv;
    744  return NS_OK;
    745 }
    746 
    747 nsresult nsIXPConnect::JSValToVariant(JSContext* cx, HandleValue aJSVal,
    748                                      nsIVariant** aResult) {
    749  MOZ_ASSERT(aResult, "bad param");
    750 
    751  RefPtr<XPCVariant> variant = XPCVariant::newVariant(cx, aJSVal);
    752  variant.forget(aResult);
    753  NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
    754 
    755  return NS_OK;
    756 }
    757 
    758 nsresult nsIXPConnect::WrapJSAggregatedToNative(nsISupports* aOuter,
    759                                                JSContext* aJSContext,
    760                                                JSObject* aJSObjArg,
    761                                                const nsIID& aIID,
    762                                                void** result) {
    763  MOZ_ASSERT(aOuter, "bad param");
    764  MOZ_ASSERT(aJSContext, "bad param");
    765  MOZ_ASSERT(aJSObjArg, "bad param");
    766  MOZ_ASSERT(result, "bad param");
    767 
    768  *result = nullptr;
    769 
    770  RootedObject aJSObj(aJSContext, aJSObjArg);
    771  nsresult rv;
    772  if (!XPCConvert::JSObject2NativeInterface(aJSContext, result, aJSObj, &aIID,
    773                                            aOuter, &rv))
    774    return rv;
    775  return NS_OK;
    776 }
    777 
    778 nsresult nsIXPConnect::GetWrappedNativeOfJSObject(
    779    JSContext* aJSContext, JSObject* aJSObjArg,
    780    nsIXPConnectWrappedNative** _retval) {
    781  MOZ_ASSERT(aJSContext, "bad param");
    782  MOZ_ASSERT(aJSObjArg, "bad param");
    783  MOZ_ASSERT(_retval, "bad param");
    784 
    785  RootedObject aJSObj(aJSContext, aJSObjArg);
    786  aJSObj = js::CheckedUnwrapDynamic(aJSObj, aJSContext,
    787                                    /* stopAtWindowProxy = */ false);
    788  if (!aJSObj || !IsWrappedNativeReflector(aJSObj)) {
    789    *_retval = nullptr;
    790    return NS_ERROR_FAILURE;
    791  }
    792 
    793  RefPtr<XPCWrappedNative> temp = XPCWrappedNative::Get(aJSObj);
    794  temp.forget(_retval);
    795  return NS_OK;
    796 }
    797 
    798 static already_AddRefed<nsISupports> ReflectorToISupports(JSObject* reflector) {
    799  if (!reflector) {
    800    return nullptr;
    801  }
    802 
    803  // Try XPCWrappedNatives.
    804  if (IsWrappedNativeReflector(reflector)) {
    805    XPCWrappedNative* wn = XPCWrappedNative::Get(reflector);
    806    if (!wn) {
    807      return nullptr;
    808    }
    809    nsCOMPtr<nsISupports> native = wn->Native();
    810    return native.forget();
    811  }
    812 
    813  // Try DOM objects.  This QI without taking a ref first is safe, because
    814  // this if non-null our thing will definitely be a DOM object, and we know
    815  // their QI to nsISupports doesn't do anything weird.
    816  nsCOMPtr<nsISupports> canonical =
    817      do_QueryInterface(mozilla::dom::UnwrapDOMObjectToISupports(reflector));
    818  return canonical.forget();
    819 }
    820 
    821 already_AddRefed<nsISupports> xpc::ReflectorToISupportsStatic(
    822    JSObject* reflector) {
    823  // Unwrap security wrappers, if allowed.
    824  return ReflectorToISupports(js::CheckedUnwrapStatic(reflector));
    825 }
    826 
    827 already_AddRefed<nsISupports> xpc::ReflectorToISupportsDynamic(
    828    JSObject* reflector, JSContext* cx) {
    829  // Unwrap security wrappers, if allowed.
    830  return ReflectorToISupports(
    831      js::CheckedUnwrapDynamic(reflector, cx,
    832                               /* stopAtWindowProxy = */ false));
    833 }
    834 
    835 nsresult nsIXPConnect::CreateSandbox(JSContext* cx, nsIPrincipal* principal,
    836                                     JSObject** _retval) {
    837  *_retval = nullptr;
    838 
    839  RootedValue rval(cx);
    840  SandboxOptions options;
    841  nsresult rv = CreateSandboxObject(cx, &rval, principal, options);
    842  MOZ_ASSERT(NS_FAILED(rv) || !rval.isPrimitive(),
    843             "Bad return value from xpc_CreateSandboxObject()!");
    844 
    845  if (NS_SUCCEEDED(rv) && !rval.isPrimitive()) {
    846    *_retval = rval.toObjectOrNull();
    847  }
    848 
    849  return rv;
    850 }
    851 
    852 nsresult nsIXPConnect::EvalInSandboxObject(const nsAString& source,
    853                                           const char* filename, JSContext* cx,
    854                                           JSObject* sandboxArg,
    855                                           MutableHandleValue rval) {
    856  if (!sandboxArg) {
    857    return NS_ERROR_INVALID_ARG;
    858  }
    859 
    860  RootedObject sandbox(cx, sandboxArg);
    861  nsCString filenameStr;
    862  if (filename) {
    863    filenameStr.Assign(filename);
    864  } else {
    865    filenameStr = "x-bogus://XPConnect/Sandbox"_ns;
    866  }
    867  return EvalInSandbox(cx, sandbox, source, filenameStr, 1,
    868                       /* enforceFilenameRestrictions */ true, rval);
    869 }
    870 
    871 nsresult nsIXPConnect::DebugDump(int16_t depth) {
    872 #ifdef DEBUG
    873  auto* self = static_cast<nsXPConnect*>(this);
    874 
    875  depth--;
    876  XPC_LOG_ALWAYS(
    877      ("nsXPConnect @ %p with mRefCnt = %" PRIuPTR, self, self->mRefCnt.get()));
    878  XPC_LOG_INDENT();
    879  XPC_LOG_ALWAYS(("gSelf @ %p", self->gSelf));
    880  XPC_LOG_ALWAYS(("gOnceAliveNowDead is %d", (int)self->gOnceAliveNowDead));
    881  XPCWrappedNativeScope::DebugDumpAllScopes(depth);
    882  XPC_LOG_OUTDENT();
    883 #endif
    884  return NS_OK;
    885 }
    886 
    887 nsresult nsIXPConnect::DebugDumpObject(nsISupports* aCOMObj, int16_t depth) {
    888 #ifdef DEBUG
    889  if (!depth) {
    890    return NS_OK;
    891  }
    892  if (!aCOMObj) {
    893    XPC_LOG_ALWAYS(("*** Cound not dump object with NULL address"));
    894    return NS_OK;
    895  }
    896 
    897  nsCOMPtr<nsIXPConnect> xpc;
    898  nsCOMPtr<nsIXPConnectWrappedNative> wn;
    899  nsCOMPtr<nsIXPConnectWrappedJS> wjs;
    900 
    901  if (NS_SUCCEEDED(aCOMObj->QueryInterface(NS_GET_IID(nsIXPConnect),
    902                                           getter_AddRefs(xpc)))) {
    903    XPC_LOG_ALWAYS(("Dumping a nsIXPConnect..."));
    904    xpc->DebugDump(depth);
    905  } else if (NS_SUCCEEDED(aCOMObj->QueryInterface(
    906                 NS_GET_IID(nsIXPConnectWrappedNative), getter_AddRefs(wn)))) {
    907    XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedNative..."));
    908    wn->DebugDump(depth);
    909  } else if (NS_SUCCEEDED(aCOMObj->QueryInterface(
    910                 NS_GET_IID(nsIXPConnectWrappedJS), getter_AddRefs(wjs)))) {
    911    XPC_LOG_ALWAYS(("Dumping a nsIXPConnectWrappedJS..."));
    912    wjs->DebugDump(depth);
    913  } else {
    914    XPC_LOG_ALWAYS(("*** Could not dump the nsISupports @ %p", aCOMObj));
    915  }
    916 #endif
    917  return NS_OK;
    918 }
    919 
    920 nsresult nsIXPConnect::DebugDumpJSStack(bool showArgs, bool showLocals,
    921                                        bool showThisProps) {
    922  xpc_DumpJSStack(showArgs, showLocals, showThisProps);
    923 
    924  return NS_OK;
    925 }
    926 
    927 nsresult nsIXPConnect::VariantToJS(JSContext* ctx, JSObject* scopeArg,
    928                                   nsIVariant* value,
    929                                   MutableHandleValue _retval) {
    930  MOZ_ASSERT(ctx, "bad param");
    931  MOZ_ASSERT(scopeArg, "bad param");
    932  MOZ_ASSERT(value, "bad param");
    933 
    934  RootedObject scope(ctx, scopeArg);
    935  MOZ_ASSERT(js::IsObjectInContextCompartment(scope, ctx));
    936 
    937  nsresult rv = NS_OK;
    938  if (!XPCVariant::VariantDataToJS(ctx, value, &rv, _retval)) {
    939    if (NS_FAILED(rv)) {
    940      return rv;
    941    }
    942 
    943    return NS_ERROR_FAILURE;
    944  }
    945  return NS_OK;
    946 }
    947 
    948 nsresult nsIXPConnect::JSToVariant(JSContext* ctx, HandleValue value,
    949                                   nsIVariant** _retval) {
    950  MOZ_ASSERT(ctx, "bad param");
    951  MOZ_ASSERT(_retval, "bad param");
    952 
    953  RefPtr<XPCVariant> variant = XPCVariant::newVariant(ctx, value);
    954  variant.forget(_retval);
    955  if (!(*_retval)) {
    956    return NS_ERROR_FAILURE;
    957  }
    958 
    959  return NS_OK;
    960 }
    961 
    962 namespace xpc {
    963 
    964 bool Base64Encode(JSContext* cx, HandleValue val, MutableHandleValue out) {
    965  MOZ_ASSERT(cx);
    966 
    967  nsAutoCString encodedString;
    968  BindingCallContext callCx(cx, "Base64Encode");
    969  if (!ConvertJSValueToByteString(callCx, val, false, "value", encodedString)) {
    970    return false;
    971  }
    972 
    973  nsAutoCString result;
    974  if (NS_FAILED(mozilla::Base64Encode(encodedString, result))) {
    975    JS_ReportErrorASCII(cx, "Failed to encode base64 data!");
    976    return false;
    977  }
    978 
    979  JSString* str = JS_NewStringCopyN(cx, result.get(), result.Length());
    980  if (!str) {
    981    return false;
    982  }
    983 
    984  out.setString(str);
    985  return true;
    986 }
    987 
    988 bool Base64Decode(JSContext* cx, HandleValue val, MutableHandleValue out) {
    989  MOZ_ASSERT(cx);
    990 
    991  nsAutoCString encodedString;
    992  BindingCallContext callCx(cx, "Base64Decode");
    993  if (!ConvertJSValueToByteString(callCx, val, false, "value", encodedString)) {
    994    return false;
    995  }
    996 
    997  nsAutoCString result;
    998  if (NS_FAILED(mozilla::Base64Decode(encodedString, result))) {
    999    JS_ReportErrorASCII(cx, "Failed to decode base64 string!");
   1000    return false;
   1001  }
   1002 
   1003  JSString* str = JS_NewStringCopyN(cx, result.get(), result.Length());
   1004  if (!str) {
   1005    return false;
   1006  }
   1007 
   1008  out.setString(str);
   1009  return true;
   1010 }
   1011 
   1012 void SetLocationForGlobal(JSObject* global, const nsACString& location) {
   1013  MOZ_ASSERT(global);
   1014  RealmPrivate::Get(global)->SetLocation(location);
   1015 }
   1016 
   1017 void SetLocationForGlobal(JSObject* global, nsIURI* locationURI) {
   1018  MOZ_ASSERT(global);
   1019  RealmPrivate::Get(global)->SetLocationURI(locationURI);
   1020 }
   1021 
   1022 }  // namespace xpc
   1023 
   1024 // static
   1025 nsIXPConnect* nsIXPConnect::XPConnect() {
   1026  // Do a release-mode assert that we're not doing anything significant in
   1027  // XPConnect off the main thread. If you're an extension developer hitting
   1028  // this, you need to change your code. See bug 716167.
   1029  if (!MOZ_LIKELY(NS_IsMainThread())) {
   1030    MOZ_CRASH();
   1031  }
   1032 
   1033  return nsXPConnect::gSelf;
   1034 }
   1035 
   1036 /* These are here to be callable from a debugger */
   1037 extern "C" {
   1038 
   1039 MOZ_EXPORT void DumpJSStack() { xpc_DumpJSStack(true, true, false); }
   1040 
   1041 MOZ_EXPORT void DumpCompleteHeap() {
   1042  nsCOMPtr<nsICycleCollectorListener> listener =
   1043      nsCycleCollector_createLogger();
   1044  MOZ_ASSERT(listener);
   1045 
   1046  nsCOMPtr<nsICycleCollectorListener> alltracesListener;
   1047  listener->AllTraces(getter_AddRefs(alltracesListener));
   1048  if (!alltracesListener) {
   1049    NS_WARNING("Failed to get all traces logger");
   1050    return;
   1051  }
   1052 
   1053  nsJSContext::CycleCollectNow(CCReason::DUMP_HEAP, alltracesListener);
   1054 }
   1055 
   1056 }  // extern "C"
   1057 
   1058 namespace xpc {
   1059 
   1060 bool Atob(JSContext* cx, unsigned argc, Value* vp) {
   1061  CallArgs args = CallArgsFromVp(argc, vp);
   1062  if (!args.length()) {
   1063    return true;
   1064  }
   1065 
   1066  return xpc::Base64Decode(cx, args[0], args.rval());
   1067 }
   1068 
   1069 bool Btoa(JSContext* cx, unsigned argc, Value* vp) {
   1070  CallArgs args = CallArgsFromVp(argc, vp);
   1071  if (!args.length()) {
   1072    return true;
   1073  }
   1074 
   1075  return xpc::Base64Encode(cx, args[0], args.rval());
   1076 }
   1077 
   1078 bool IsXrayWrapper(JSObject* obj) { return WrapperFactory::IsXrayWrapper(obj); }
   1079 
   1080 }  // namespace xpc
   1081 
   1082 namespace mozilla {
   1083 namespace dom {
   1084 
   1085 bool IsChromeOrUAWidget(JSContext* cx, JSObject* /* unused */) {
   1086  MOZ_ASSERT(NS_IsMainThread());
   1087  JS::Realm* realm = JS::GetCurrentRealmOrNull(cx);
   1088  MOZ_ASSERT(realm);
   1089  JS::Compartment* c = JS::GetCompartmentForRealm(realm);
   1090 
   1091  return AccessCheck::isChrome(c) || IsUAWidgetCompartment(c);
   1092 }
   1093 
   1094 bool IsNotUAWidget(JSContext* cx, JSObject* /* unused */) {
   1095  MOZ_ASSERT(NS_IsMainThread());
   1096  JS::Realm* realm = JS::GetCurrentRealmOrNull(cx);
   1097  MOZ_ASSERT(realm);
   1098  JS::Compartment* c = JS::GetCompartmentForRealm(realm);
   1099 
   1100  return !IsUAWidgetCompartment(c);
   1101 }
   1102 
   1103 extern bool IsCurrentThreadRunningChromeWorker();
   1104 
   1105 bool ThreadSafeIsChromeOrUAWidget(JSContext* cx, JSObject* obj) {
   1106  if (NS_IsMainThread()) {
   1107    return IsChromeOrUAWidget(cx, obj);
   1108  }
   1109  return IsCurrentThreadRunningChromeWorker();
   1110 }
   1111 
   1112 }  // namespace dom
   1113 }  // namespace mozilla
   1114 
   1115 #ifdef MOZ_TSAN
   1116 ReadOnlyPage ReadOnlyPage::sInstance;
   1117 #else
   1118 constexpr const volatile ReadOnlyPage ReadOnlyPage::sInstance;
   1119 #endif
   1120 
   1121 void xpc::ReadOnlyPage::Write(const volatile bool* aPtr, bool aValue) {
   1122  MOZ_RELEASE_ASSERT(NS_IsMainThread());
   1123  if (*aPtr == aValue) return;
   1124  // Please modify the definition of kAutomationPageSize if a new platform
   1125  // is running in automation and hits this assertion.
   1126  MOZ_RELEASE_ASSERT(PR_GetPageSize() == alignof(ReadOnlyPage));
   1127  MOZ_RELEASE_ASSERT(
   1128      reinterpret_cast<uintptr_t>(&sInstance) % alignof(ReadOnlyPage) == 0);
   1129 #ifdef XP_WIN
   1130  AutoVirtualProtect prot(const_cast<ReadOnlyPage*>(&sInstance),
   1131                          alignof(ReadOnlyPage), PAGE_READWRITE);
   1132  MOZ_RELEASE_ASSERT(prot && (prot.PrevProt() & 0xFF) == PAGE_READONLY);
   1133 #else
   1134  int ret = mprotect(const_cast<ReadOnlyPage*>(&sInstance),
   1135                     alignof(ReadOnlyPage), PROT_READ | PROT_WRITE);
   1136  MOZ_RELEASE_ASSERT(ret == 0);
   1137 #endif
   1138  MOZ_RELEASE_ASSERT(aPtr == &sInstance.mNonLocalConnectionsDisabled ||
   1139                     aPtr == &sInstance.mTurnOffAllSecurityPref);
   1140 #ifdef XP_WIN
   1141  BOOL ret = WriteProcessMemory(GetCurrentProcess(), const_cast<bool*>(aPtr),
   1142                                &aValue, sizeof(bool), nullptr);
   1143  MOZ_RELEASE_ASSERT(ret);
   1144 #else
   1145  *const_cast<volatile bool*>(aPtr) = aValue;
   1146  ret = mprotect(const_cast<ReadOnlyPage*>(&sInstance), alignof(ReadOnlyPage),
   1147                 PROT_READ);
   1148  MOZ_RELEASE_ASSERT(ret == 0);
   1149 #endif
   1150 }
   1151 
   1152 void xpc::ReadOnlyPage::Init() {
   1153  MOZ_RELEASE_ASSERT(NS_IsMainThread());
   1154  static_assert(alignof(ReadOnlyPage) == kAutomationPageSize);
   1155  static_assert(sizeof(sInstance) == alignof(ReadOnlyPage));
   1156 
   1157  // Make sure that initialization is not too late.
   1158  MOZ_DIAGNOSTIC_ASSERT(!net::gIOService);
   1159  char* s = getenv("MOZ_DISABLE_NONLOCAL_CONNECTIONS");
   1160  const bool disabled = s && *s != '0';
   1161  Write(&sInstance.mNonLocalConnectionsDisabled, disabled);
   1162  if (!disabled) {
   1163    // not bothered to check automation prefs.
   1164    return;
   1165  }
   1166 
   1167  // The obvious thing is to make this pref a static pref. But then it would
   1168  // always be defined and always show up in about:config, and users could flip
   1169  // it, which we don't want. Instead we roll our own callback so that if the
   1170  // pref is undefined (the normal case) then sAutomationPrefIsSet is false and
   1171  // nothing shows up in about:config.
   1172  nsresult rv = Preferences::RegisterCallbackAndCall(
   1173      [](const char* aPrefName, void* /* aClosure */) {
   1174        Write(&sInstance.mTurnOffAllSecurityPref,
   1175              Preferences::GetBool(aPrefName, /* aFallback */ false));
   1176      },
   1177      "security."
   1178      "turn_off_all_security_so_that_viruses_can_take_over_this_computer");
   1179  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
   1180 }