int XRE_XPCShellMain(int argc, char** argv, char** envp) { JSRuntime* rt; JSContext* cx; int result; nsresult rv; gErrFile = stderr; gOutFile = stdout; gInFile = stdin; NS_LogInit(); // A initializer to initialize histogram collection // used by telemetry. UniquePtr<base::StatisticsRecorder> telStats = MakeUnique<base::StatisticsRecorder>(); nsCOMPtr<nsIFile> appFile; rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(appFile)); if (NS_FAILED(rv)) { printf("Couldn't find application file.\n"); return 1; } nsCOMPtr<nsIFile> appDir; rv = appFile->GetParent(getter_AddRefs(appDir)); if (NS_FAILED(rv)) { printf("Couldn't get application directory.\n"); return 1; } XPCShellDirProvider dirprovider; dirprovider.SetAppFile(appFile); nsCOMPtr<nsIFile> greDir; if (argc > 1 && !strcmp(argv[1], "-g")) { if (argc < 3) return usage(); rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(greDir)); if (NS_FAILED(rv)) { printf("Couldn't use given GRE dir.\n"); return 1; } dirprovider.SetGREDirs(greDir); argc -= 2; argv += 2; } else { #ifdef XP_MACOSX // On OSX, the GreD needs to point to Contents/Resources in the .app // bundle. Libraries will be loaded at a relative path to GreD, i.e. // ../MacOS. nsCOMPtr<nsIFile> tmpDir; XRE_GetFileFromPath(argv[0], getter_AddRefs(greDir)); greDir->GetParent(getter_AddRefs(tmpDir)); tmpDir->Clone(getter_AddRefs(greDir)); tmpDir->SetNativeLeafName(NS_LITERAL_CSTRING("Resources")); bool dirExists = false; tmpDir->Exists(&dirExists); if (dirExists) { greDir = tmpDir.forget(); } dirprovider.SetGREDirs(greDir); #else nsAutoString workingDir; if (!GetCurrentWorkingDirectory(workingDir)) { printf("GetCurrentWorkingDirectory failed.\n"); return 1; } rv = NS_NewLocalFile(workingDir, true, getter_AddRefs(greDir)); if (NS_FAILED(rv)) { printf("NS_NewLocalFile failed.\n"); return 1; } #endif } if (argc > 1 && !strcmp(argv[1], "-a")) { if (argc < 3) return usage(); nsCOMPtr<nsIFile> dir; rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(dir)); if (NS_SUCCEEDED(rv)) { appDir = do_QueryInterface(dir, &rv); dirprovider.SetAppDir(appDir); } if (NS_FAILED(rv)) { printf("Couldn't use given appdir.\n"); return 1; } argc -= 2; argv += 2; } while (argc > 1 && !strcmp(argv[1], "-r")) { if (argc < 3) return usage(); nsCOMPtr<nsIFile> lf; rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(lf)); if (NS_FAILED(rv)) { printf("Couldn't get manifest file.\n"); return 1; } XRE_AddManifestLocation(NS_COMPONENT_LOCATION, lf); argc -= 2; argv += 2; } #ifdef MOZ_CRASHREPORTER const char* val = getenv("MOZ_CRASHREPORTER"); if (val && *val) { rv = CrashReporter::SetExceptionHandler(greDir, true); if (NS_FAILED(rv)) { printf("CrashReporter::SetExceptionHandler failed!\n"); return 1; } MOZ_ASSERT(CrashReporter::GetEnabled()); } #endif { if (argc > 1 && !strcmp(argv[1], "--greomni")) { nsCOMPtr<nsIFile> greOmni; nsCOMPtr<nsIFile> appOmni; XRE_GetFileFromPath(argv[2], getter_AddRefs(greOmni)); if (argc > 3 && !strcmp(argv[3], "--appomni")) { XRE_GetFileFromPath(argv[4], getter_AddRefs(appOmni)); argc-=2; argv+=2; } else { appOmni = greOmni; } XRE_InitOmnijar(greOmni, appOmni); argc-=2; argv+=2; } nsCOMPtr<nsIServiceManager> servMan; rv = NS_InitXPCOM2(getter_AddRefs(servMan), appDir, &dirprovider); if (NS_FAILED(rv)) { printf("NS_InitXPCOM2 failed!\n"); return 1; } nsCOMPtr<nsIJSRuntimeService> rtsvc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1"); // get the JSRuntime from the runtime svc if (!rtsvc) { printf("failed to get nsJSRuntimeService!\n"); return 1; } if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) { printf("failed to get JSRuntime from nsJSRuntimeService!\n"); return 1; } // Override the default XPConnect interrupt callback. We could store the // old one and restore it before shutting down, but there's not really a // reason to bother. sScriptedInterruptCallback.init(rt, UndefinedValue()); JS_SetInterruptCallback(rt, XPCShellInterruptCallback); JS_SetErrorReporter(rt, XPCShellErrorReporter); dom::AutoJSAPI jsapi; jsapi.Init(); cx = jsapi.cx(); argc--; argv++; ProcessArgsForCompartment(cx, argv, argc); nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID()); if (!xpc) { printf("failed to get nsXPConnect service!\n"); return 1; } nsCOMPtr<nsIPrincipal> systemprincipal; // Fetch the system principal and store it away in a global, to use for // script compilation in Load() and ProcessFile() (including interactive // eval loop) { nsCOMPtr<nsIScriptSecurityManager> securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_SUCCEEDED(rv) && securityManager) { rv = securityManager->GetSystemPrincipal(getter_AddRefs(systemprincipal)); if (NS_FAILED(rv)) { fprintf(gErrFile, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n"); } else { // fetch the JS principals and stick in a global gJSPrincipals = nsJSPrincipals::get(systemprincipal); JS_HoldPrincipals(gJSPrincipals); } } else { fprintf(gErrFile, "+++ Failed to get ScriptSecurityManager service, running without principals"); } } const JSSecurityCallbacks* scb = JS_GetSecurityCallbacks(rt); MOZ_ASSERT(scb, "We are assuming that nsScriptSecurityManager::Init() has been run"); shellSecurityCallbacks = *scb; JS_SetSecurityCallbacks(rt, &shellSecurityCallbacks); #ifdef TEST_TranslateThis nsCOMPtr<nsIXPCFunctionThisTranslator> translator(new nsXPCFunctionThisTranslator); xpc->SetFunctionThisTranslator(NS_GET_IID(nsITestXPCFunctionCallback), translator); #endif nsRefPtr<BackstagePass> backstagePass; rv = NS_NewBackstagePass(getter_AddRefs(backstagePass)); if (NS_FAILED(rv)) { fprintf(gErrFile, "+++ Failed to create BackstagePass: %8x\n", static_cast<uint32_t>(rv)); return 1; } // Make the default XPCShell global use a fresh zone (rather than the // System Zone) to improve cross-zone test coverage. JS::CompartmentOptions options; options.setZone(JS::FreshZone) .setVersion(JSVERSION_LATEST); nsCOMPtr<nsIXPConnectJSObjectHolder> holder; rv = xpc->InitClassesWithNewWrappedGlobal(cx, static_cast<nsIGlobalObject*>(backstagePass), systemprincipal, 0, options, getter_AddRefs(holder)); if (NS_FAILED(rv)) return 1; { JS::Rooted<JSObject*> glob(cx, holder->GetJSObject()); if (!glob) { return 1; } // Even if we're building in a configuration where source is // discarded, there's no reason to do that on XPCShell, and doing so // might break various automation scripts. JS::CompartmentOptionsRef(glob).setDiscardSource(false); backstagePass->SetGlobalObject(glob); JSAutoCompartment ac(cx, glob); if (!JS_InitReflect(cx, glob)) { return 1; } if (!JS_DefineFunctions(cx, glob, glob_functions) || !JS_DefineProfilingFunctions(cx, glob)) { return 1; } JS::Rooted<JSObject*> envobj(cx); envobj = JS_DefineObject(cx, glob, "environment", &env_class); if (!envobj) { return 1; } JS_SetPrivate(envobj, envp); nsAutoString workingDirectory; if (GetCurrentWorkingDirectory(workingDirectory)) gWorkingDirectory = &workingDirectory; JS_DefineProperty(cx, glob, "__LOCATION__", JS::UndefinedHandleValue, JSPROP_SHARED, GetLocationProperty, nullptr); // We are almost certainly going to run script here, so we need an // AutoEntryScript. This is Gecko-specific and not in any spec. dom::AutoEntryScript aes(backstagePass); result = ProcessArgs(aes.cx(), glob, argv, argc, &dirprovider); JS_DropPrincipals(rt, gJSPrincipals); JS_SetAllNonReservedSlotsToUndefined(aes.cx(), glob); JS_GC(rt); } JS_GC(rt); } // this scopes the nsCOMPtrs if (!XRE_ShutdownTestShell()) NS_ERROR("problem shutting down testshell"); // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM rv = NS_ShutdownXPCOM( nullptr ); MOZ_ASSERT(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN // test of late call and release (see above) JSContext* bogusCX; bogus->Peek(&bogusCX); bogus = nullptr; #endif telStats = nullptr; appDir = nullptr; appFile = nullptr; dirprovider.ClearGREDirs(); dirprovider.ClearAppDir(); dirprovider.ClearPluginDir(); dirprovider.ClearAppFile(); #ifdef MOZ_CRASHREPORTER // Shut down the crashreporter service to prevent leaking some strings it holds. if (CrashReporter::GetEnabled()) CrashReporter::UnsetExceptionHandler(); #endif NS_LogTerm(); return result; }
int XRE_XPCShellMain(int argc, char **argv, char **envp) { JSRuntime *rt; JSContext *cx; int result; nsresult rv; gErrFile = stderr; gOutFile = stdout; gInFile = stdin; NS_LogInit(); nsCOMPtr<nsIFile> appFile; rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(appFile)); if (NS_FAILED(rv)) { printf("Couldn't find application file.\n"); return 1; } nsCOMPtr<nsIFile> appDir; rv = appFile->GetParent(getter_AddRefs(appDir)); if (NS_FAILED(rv)) { printf("Couldn't get application directory.\n"); return 1; } XPCShellDirProvider dirprovider; dirprovider.SetAppFile(appFile); if (argc > 1 && !strcmp(argv[1], "-g")) { if (argc < 3) return usage(); if (!dirprovider.SetGREDir(argv[2])) { printf("SetGREDir failed.\n"); return 1; } argc -= 2; argv += 2; } if (argc > 1 && !strcmp(argv[1], "-a")) { if (argc < 3) return usage(); nsCOMPtr<nsIFile> dir; rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(dir)); if (NS_SUCCEEDED(rv)) { appDir = do_QueryInterface(dir, &rv); dirprovider.SetAppDir(appDir); } if (NS_FAILED(rv)) { printf("Couldn't use given appdir.\n"); return 1; } argc -= 2; argv += 2; } while (argc > 1 && !strcmp(argv[1], "-r")) { if (argc < 3) return usage(); nsCOMPtr<nsIFile> lf; rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(lf)); if (NS_FAILED(rv)) { printf("Couldn't get manifest file.\n"); return 1; } XRE_AddManifestLocation(NS_COMPONENT_LOCATION, lf); argc -= 2; argv += 2; } #ifdef MOZ_CRASHREPORTER // This is needed during startup and also shutdown, so keep it out // of the nested scope. // Special exception: will remain usable after NS_ShutdownXPCOM nsCOMPtr<nsICrashReporter> crashReporter; #endif { if (argc > 1 && !strcmp(argv[1], "--greomni")) { nsCOMPtr<nsIFile> greOmni; nsCOMPtr<nsIFile> appOmni; XRE_GetFileFromPath(argv[2], getter_AddRefs(greOmni)); if (argc > 3 && !strcmp(argv[3], "--appomni")) { XRE_GetFileFromPath(argv[4], getter_AddRefs(appOmni)); argc-=2; argv+=2; } else { appOmni = greOmni; } XRE_InitOmnijar(greOmni, appOmni); argc-=2; argv+=2; } nsCOMPtr<nsIServiceManager> servMan; rv = NS_InitXPCOM2(getter_AddRefs(servMan), appDir, &dirprovider); if (NS_FAILED(rv)) { printf("NS_InitXPCOM2 failed!\n"); return 1; } #ifdef MOZ_CRASHREPORTER const char *val = getenv("MOZ_CRASHREPORTER"); crashReporter = do_GetService("@mozilla.org/toolkit/crash-reporter;1"); if (val && *val) { crashReporter->SetEnabled(true); } #endif nsCOMPtr<nsIJSRuntimeService> rtsvc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1"); // get the JSRuntime from the runtime svc if (!rtsvc) { printf("failed to get nsJSRuntimeService!\n"); return 1; } if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) { printf("failed to get JSRuntime from nsJSRuntimeService!\n"); return 1; } rtsvc->RegisterContextCallback(ContextCallback); // Override the default XPConnect operation callback. We could store the // old one and restore it before shutting down, but there's not really a // reason to bother. JS_SetOperationCallback(rt, XPCShellOperationCallback); cx = JS_NewContext(rt, 8192); if (!cx) { printf("JS_NewContext failed!\n"); return 1; } argc--; argv++; ProcessArgsForCompartment(cx, argv, argc); nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID()); if (!xpc) { printf("failed to get nsXPConnect service!\n"); return 1; } nsCOMPtr<nsIPrincipal> systemprincipal; // Fetch the system principal and store it away in a global, to use for // script compilation in Load() and ProcessFile() (including interactive // eval loop) { nsCOMPtr<nsIScriptSecurityManager> securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_SUCCEEDED(rv) && securityManager) { rv = securityManager->GetSystemPrincipal(getter_AddRefs(systemprincipal)); if (NS_FAILED(rv)) { fprintf(gErrFile, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n"); } else { // fetch the JS principals and stick in a global gJSPrincipals = nsJSPrincipals::get(systemprincipal); JS_HoldPrincipals(gJSPrincipals); } } else { fprintf(gErrFile, "+++ Failed to get ScriptSecurityManager service, running without principals"); } } const JSSecurityCallbacks *scb = JS_GetSecurityCallbacks(rt); MOZ_ASSERT(scb, "We are assuming that nsScriptSecurityManager::Init() has been run"); shellSecurityCallbacks = *scb; JS_SetSecurityCallbacks(rt, &shellSecurityCallbacks); #ifdef TEST_TranslateThis nsCOMPtr<nsIXPCFunctionThisTranslator> translator(new nsXPCFunctionThisTranslator); xpc->SetFunctionThisTranslator(NS_GET_IID(nsITestXPCFunctionCallback), translator); #endif nsCxPusher pusher; pusher.Push(cx); nsRefPtr<BackstagePass> backstagePass; rv = NS_NewBackstagePass(getter_AddRefs(backstagePass)); if (NS_FAILED(rv)) { fprintf(gErrFile, "+++ Failed to create BackstagePass: %8x\n", static_cast<uint32_t>(rv)); return 1; } JS::CompartmentOptions options; options.setZone(JS::SystemZone) .setVersion(JSVERSION_LATEST); nsCOMPtr<nsIXPConnectJSObjectHolder> holder; rv = xpc->InitClassesWithNewWrappedGlobal(cx, static_cast<nsIGlobalObject *>(backstagePass), systemprincipal, 0, options, getter_AddRefs(holder)); if (NS_FAILED(rv)) return 1; { JS::Rooted<JSObject*> glob(cx, holder->GetJSObject()); if (!glob) { return 1; } backstagePass->SetGlobalObject(glob); JSAutoCompartment ac(cx, glob); if (!JS_InitReflect(cx, glob)) { JS_EndRequest(cx); return 1; } if (!JS_DefineFunctions(cx, glob, glob_functions) || !JS_DefineProfilingFunctions(cx, glob)) { JS_EndRequest(cx); return 1; } JS::Rooted<JSObject*> envobj(cx); envobj = JS_DefineObject(cx, glob, "environment", &env_class, nullptr, 0); if (!envobj) { JS_EndRequest(cx); return 1; } JS_SetPrivate(envobj, envp); nsAutoString workingDirectory; if (GetCurrentWorkingDirectory(workingDirectory)) gWorkingDirectory = &workingDirectory; JS_DefineProperty(cx, glob, "__LOCATION__", JSVAL_VOID, GetLocationProperty, nullptr, 0); JS_AddValueRoot(cx, &sScriptedOperationCallback); result = ProcessArgs(cx, glob, argv, argc, &dirprovider); JS_RemoveValueRoot(cx, &sScriptedOperationCallback); JS_DropPrincipals(rt, gJSPrincipals); JS_SetAllNonReservedSlotsToUndefined(cx, glob); JS_GC(rt); } pusher.Pop(); JS_GC(rt); JS_DestroyContext(cx); } // this scopes the nsCOMPtrs if (!XRE_ShutdownTestShell()) NS_ERROR("problem shutting down testshell"); // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM rv = NS_ShutdownXPCOM( nullptr ); MOZ_ASSERT(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN // test of late call and release (see above) JSContext* bogusCX; bogus->Peek(&bogusCX); bogus = nullptr; #endif appDir = nullptr; appFile = nullptr; dirprovider.ClearGREDir(); dirprovider.ClearAppDir(); dirprovider.ClearPluginDir(); dirprovider.ClearAppFile(); #ifdef MOZ_CRASHREPORTER // Shut down the crashreporter service to prevent leaking some strings it holds. if (crashReporter) { crashReporter->SetEnabled(false); crashReporter = nullptr; } #endif NS_LogTerm(); return result; }