diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 480bc4280f7c..19ea221d4c31 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -85,7 +85,6 @@ using namespace mozilla; using namespace mozilla::dom; nsIIOService* nsScriptSecurityManager::sIOService = nullptr; -JSContext* nsScriptSecurityManager::sContext = nullptr; bool nsScriptSecurityManager::sStrictFileOriginPolicy = true; namespace { @@ -1371,22 +1370,28 @@ nsresult nsScriptSecurityManager::Init() { mSystemPrincipal = system; + return NS_OK; +} + +void nsScriptSecurityManager::InitJSCallbacks(JSContext* aCx) { //-- Register security check callback in the JS engine // Currently this is used to control access to function.caller - sContext = danger::GetJSContext(); static const JSSecurityCallbacks securityCallbacks = { ContentSecurityPolicyPermitsJSAction, JSPrincipalsSubsume, }; - MOZ_ASSERT(!JS_GetSecurityCallbacks(sContext)); - JS_SetSecurityCallbacks(sContext, &securityCallbacks); - JS_InitDestroyPrincipalsCallback(sContext, nsJSPrincipals::Destroy); + MOZ_ASSERT(!JS_GetSecurityCallbacks(aCx)); + JS_SetSecurityCallbacks(aCx, &securityCallbacks); + JS_InitDestroyPrincipalsCallback(aCx, nsJSPrincipals::Destroy); - JS_SetTrustedPrincipals(sContext, system); + JS_SetTrustedPrincipals(aCx, BasePrincipal::Cast(mSystemPrincipal)); +} - return NS_OK; +void nsScriptSecurityManager::ClearJSCallbacks(JSContext* aCx) { + JS_SetSecurityCallbacks(aCx, nullptr); + JS_SetTrustedPrincipals(aCx, nullptr); } static StaticRefPtr gScriptSecMan; @@ -1404,12 +1409,6 @@ nsScriptSecurityManager::~nsScriptSecurityManager(void) { } void nsScriptSecurityManager::Shutdown() { - if (sContext) { - JS_SetSecurityCallbacks(sContext, nullptr); - JS_SetTrustedPrincipals(sContext, nullptr); - sContext = nullptr; - } - NS_IF_RELEASE(sIOService); BundleHelper::Shutdown(); } diff --git a/caps/nsScriptSecurityManager.h b/caps/nsScriptSecurityManager.h index b56090fcb4b0..7b99c614e987 100644 --- a/caps/nsScriptSecurityManager.h +++ b/caps/nsScriptSecurityManager.h @@ -51,6 +51,9 @@ class nsScriptSecurityManager final : public nsIScriptSecurityManager { // Invoked exactly once, by XPConnect. static void InitStatics(); + void InitJSCallbacks(JSContext* aCx); + void ClearJSCallbacks(JSContext* aCx); + static already_AddRefed SystemPrincipalSingletonConstructor(); @@ -121,7 +124,6 @@ class nsScriptSecurityManager final : public nsIScriptSecurityManager { static nsIIOService* sIOService; static nsIStringBundle* sStrBundle; - static JSContext* sContext; }; #endif // nsScriptSecurityManager_h__ diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index c21f0d8ba994..b5c1949dfbbc 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -1262,6 +1262,10 @@ nsresult XPCJSContext::Initialize() { Preferences::RegisterCallback(ReloadPrefsCallback, "fuzzing.enabled", this); #endif + MOZ_RELEASE_ASSERT(JS::InitSelfHostedCode(cx), "InitSelfHostedCode failed"); + MOZ_RELEASE_ASSERT(Runtime()->InitializeStrings(cx), + "InitializeStrings failed"); + return NS_OK; } diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index d514e1b51197..790ee7a2fd32 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -32,6 +32,7 @@ #include "nsIPlatformInfo.h" #include "nsPIDOMWindow.h" #include "nsPrintfCString.h" +#include "nsScriptSecurityManager.h" #include "nsThreadPool.h" #include "nsWindowSizes.h" #include "mozilla/Preferences.h" @@ -1135,6 +1136,8 @@ void XPCJSRuntime::Shutdown(JSContext* cx) { JS::SetGCSliceCallback(cx, mPrevGCSliceCallback); + nsScriptSecurityManager::GetScriptSecurityManager()->ClearJSCallbacks(cx); + // Shut down the helper threads gHelperThreads->Shutdown(); gHelperThreads = nullptr; @@ -3045,6 +3048,8 @@ void XPCJSRuntime::Initialize(JSContext* cx) { // these jsids filled in later when we have a JSContext to work with. mStrIDs[0] = JSID_VOID; + nsScriptSecurityManager::GetScriptSecurityManager()->InitJSCallbacks(cx); + // Unconstrain the runtime's threshold on nominal heap size, to avoid // triggering GC too often if operating continuously near an arbitrary // finite threshold (0xffffffff is infinity for uint32_t parameters). diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index a86435118f18..9b56ae4cd738 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -26,6 +26,7 @@ #include "mozilla/dom/DOMException.h" #include "mozilla/dom/Exceptions.h" #include "mozilla/dom/Promise.h" +#include "mozilla/ScriptPreloader.h" #include "nsDOMMutationObserver.h" #include "nsICycleCollectorListener.h" @@ -71,17 +72,35 @@ nsXPConnect::nsXPConnect() : mShuttingDown(false) { JS::SetProfilingThreadCallbacks(profiler_register_thread, profiler_unregister_thread); #endif +} + +// static +void nsXPConnect::InitJSContext() { + MOZ_ASSERT(!gContext); XPCJSContext* xpccx = XPCJSContext::NewXPCJSContext(); if (!xpccx) { MOZ_CRASH("Couldn't create XPCJSContext."); } gContext = xpccx; - mRuntime = xpccx->Runtime(); + gSelf->mRuntime = xpccx->Runtime(); + + // Initialize our singleton scopes. + gSelf->mRuntime->InitSingletonScopes(); + + mozJSComponentLoader::InitStatics(); + + // Initialize the script preloader cache. + Unused << mozilla::ScriptPreloader::GetSingleton(); + + nsJSContext::EnsureStatics(); } +void xpc::InitializeJSContext() { nsXPConnect::InitJSContext(); } + nsXPConnect::~nsXPConnect() { MOZ_ASSERT(XPCJSContext::Get() == gContext); + MOZ_ASSERT(mRuntime); mRuntime->DeleteSingletonScopes(); @@ -136,19 +155,6 @@ void nsXPConnect::InitStatics() { gScriptSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager(); gScriptSecurityManager->GetSystemPrincipal(&gSystemPrincipal); MOZ_RELEASE_ASSERT(gSystemPrincipal); - - JSContext* cx = XPCJSContext::Get()->Context(); - if (!JS::InitSelfHostedCode(cx)) { - MOZ_CRASH("InitSelfHostedCode failed"); - } - if (!gSelf->mRuntime->InitializeStrings(cx)) { - MOZ_CRASH("InitializeStrings failed"); - } - - // Initialize our singleton scopes. - gSelf->mRuntime->InitSingletonScopes(); - - mozJSComponentLoader::InitStatics(); } // static diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index a464b7a06efe..88fbdefa0908 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -246,6 +246,8 @@ class nsXPConnect final : public nsIXPConnect { // Called by module code on dll shutdown. static void ReleaseXPConnectSingleton(); + static void InitJSContext(); + void RecordTraversal(void* p, nsISupports* s); protected: @@ -258,7 +260,7 @@ class nsXPConnect final : public nsIXPConnect { static nsXPConnect* gSelf; static bool gOnceAliveNowDead; - XPCJSRuntime* mRuntime; + XPCJSRuntime* mRuntime = nullptr; bool mShuttingDown; friend class nsIXPConnect; diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index a4ee0c9f9d64..6ce5b436b973 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -710,6 +710,8 @@ inline bool IsInAutomation() { return sAutomationPrefIsSet && AreNonLocalConnectionsDisabled(); } +void InitializeJSContext(); + /** * Extract the native nsID object from a JS ID, IfaceID, ClassID, or ContractID * value. diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index d4be531c303b..a9393da84621 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -164,7 +164,6 @@ nsresult nsLayoutStatics::Initialize() { #endif StartupJSEnvironment(); - nsJSContext::EnsureStatics(); nsGlobalWindowInner::Init(); nsGlobalWindowOuter::Init(); diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 5a7cab7ec6eb..ba83c110f591 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -1202,7 +1202,7 @@ class ScopedXPCOMStartup { ScopedXPCOMStartup() : mServiceManager(nullptr) {} ~ScopedXPCOMStartup(); - nsresult Initialize(); + nsresult Initialize(bool aInitJSContext = true); nsresult SetWindowCreator(nsINativeAppSupport* native); private: @@ -1259,13 +1259,13 @@ static const mozilla::Module::ContractIDEntry kXREContracts[] = { extern const mozilla::Module kXREModule = {mozilla::Module::kVersion, kXRECIDs, kXREContracts}; -nsresult ScopedXPCOMStartup::Initialize() { +nsresult ScopedXPCOMStartup::Initialize(bool aInitJSContext) { NS_ASSERTION(gDirServiceProvider, "Should not get here!"); nsresult rv; rv = NS_InitXPCOM(&mServiceManager, gDirServiceProvider->GetAppDir(), - gDirServiceProvider); + gDirServiceProvider, aInitJSContext); if (NS_FAILED(rv)) { NS_ERROR("Couldn't start xpcom!"); mServiceManager = nullptr; @@ -4344,10 +4344,21 @@ nsresult XREMain::XRE_mainRun() { } } + // We'd like to initialize the JSContext *after* reading the user prefs. + // Unfortunately that's not possible if we have to do profile migration + // because that requires us to execute JS before reading user prefs. + // Restarting the browser after profile migration would fix this. See + // bug 1592523. + bool initializedJSContext = false; + { // Profile Migration if (mAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) { gDoMigration = false; + + xpc::InitializeJSContext(); + initializedJSContext = true; + nsCOMPtr pm( do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID)); if (pm) { @@ -4389,6 +4400,12 @@ nsresult XREMain::XRE_mainRun() { // ready in time for early consumers, such as the component loader. mDirProvider.InitializeUserPrefs(); + // Now that all (user) prefs have been loaded we can initialize the main + // thread's JSContext. + if (!initializedJSContext) { + xpc::InitializeJSContext(); + } + nsAppStartupNotifier::NotifyObservers(APPSTARTUP_CATEGORY); nsCOMPtr appStartup(components::AppStartup::Service()); @@ -4710,11 +4727,13 @@ int XREMain::XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig) { bool appInitiatedRestart = false; - // Start the real application + // Start the real application. We use |aInitJSContext = false| because + // XRE_mainRun wants to initialize the JSContext after reading user prefs. + mScopedXPCOM = MakeUnique(); if (!mScopedXPCOM) return 1; - rv = mScopedXPCOM->Initialize(); + rv = mScopedXPCOM->Initialize(/* aInitJSContext = */ false); NS_ENSURE_SUCCESS(rv, 1); // run! diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp index ab363081f074..d2fbc17ae95a 100644 --- a/xpcom/build/XPCOMInit.cpp +++ b/xpcom/build/XPCOMInit.cpp @@ -249,7 +249,8 @@ static bool sInitializedJS = false; // Note that on OSX, aBinDirectory will point to .app/Contents/Resources/browser EXPORT_XPCOM_API(nsresult) NS_InitXPCOM(nsIServiceManager** aResult, nsIFile* aBinDirectory, - nsIDirectoryServiceProvider* aAppFileLocationProvider) { + nsIDirectoryServiceProvider* aAppFileLocationProvider, + bool aInitJSContext) { static bool sInitialized = false; if (sInitialized) { return NS_ERROR_FAILURE; @@ -460,7 +461,6 @@ NS_InitXPCOM(nsIServiceManager** aResult, nsIFile* aBinDirectory, // Init SharedThreadPool (which needs the service manager). SharedThreadPool::InitStatics(); - mozilla::ScriptPreloader::GetSingleton(); mozilla::scache::StartupCache::GetSingleton(); mozilla::AvailableMemoryTracker::Init(); @@ -484,6 +484,10 @@ NS_InitXPCOM(nsIServiceManager** aResult, nsIFile* aBinDirectory, loop->thread_name().c_str(), loop->transient_hang_timeout(), loop->permanent_hang_timeout()); + if (aInitJSContext) { + xpc::InitializeJSContext(); + } + return NS_OK; } diff --git a/xpcom/build/nsXPCOM.h b/xpcom/build/nsXPCOM.h index ece4ce355db4..c3b33558b64e 100644 --- a/xpcom/build/nsXPCOM.h +++ b/xpcom/build/nsXPCOM.h @@ -63,6 +63,9 @@ struct Module; * component registry preferences and so on; or use * nullptr for the default behaviour. * + * @param aInitJSContext Whether the nsXPCJSContext should be initialized at + * this point. + * * @see NS_NewLocalFile * @see nsIFile * @see nsIDirectoryServiceProvider @@ -75,7 +78,8 @@ struct Module; */ XPCOM_API(nsresult) NS_InitXPCOM(nsIServiceManager** aResult, nsIFile* aBinDirectory, - nsIDirectoryServiceProvider* aAppFileLocationProvider); + nsIDirectoryServiceProvider* aAppFileLocationProvider, + bool aInitJSContext = true); /** * Initialize only minimal components of XPCOM. This ensures nsThreadManager,