예제 #1
0
JSContext*
XPCJSContextStack::GetSafeJSContext()
{
    if (mSafeJSContext)
        return mSafeJSContext;

    // Start by getting the principal holder and principal for this
    // context.  If we can't manage that, don't bother with the rest.
    nsRefPtr<nsNullPrincipal> principal = new nsNullPrincipal();
    nsresult rv = principal->Init();
    if (NS_FAILED(rv))
        MOZ_CRASH();

    nsXPConnect* xpc = nsXPConnect::XPConnect();
    JSRuntime *rt = xpc->GetRuntime()->Runtime();
    if (!rt)
        MOZ_CRASH();

    mSafeJSContext = JS_NewContext(rt, 8192);
    if (!mSafeJSContext)
        MOZ_CRASH();
    JSAutoRequest req(mSafeJSContext);

    JS::RootedObject glob(mSafeJSContext);
    JS_SetErrorReporter(mSafeJSContext, xpc::SystemErrorReporter);

    JS::CompartmentOptions options;
    options.setZone(JS::SystemZone);
    glob = xpc::CreateGlobalObject(mSafeJSContext, &SafeJSContextGlobalClass, principal, options);
    if (!glob)
        MOZ_CRASH();

    // Make sure the context is associated with a proper compartment
    // and not the default compartment.
    js::SetDefaultObjectForContext(mSafeJSContext, glob);

    // Note: make sure to set the private before calling
    // InitClasses
    nsCOMPtr<nsIScriptObjectPrincipal> sop = new SandboxPrivate(principal, glob);
    JS_SetPrivate(glob, sop.forget().get());

    // After this point either glob is null and the
    // nsIScriptObjectPrincipal ownership is either handled by the
    // nsCOMPtr or dealt with, or we'll release in the finalize
    // hook.
    if (NS_FAILED(xpc->InitClasses(mSafeJSContext, glob)))
        MOZ_CRASH();

    JS_FireOnNewGlobalObject(mSafeJSContext, glob);

    // Save it off so we can destroy it later.
    mOwnSafeJSContext = mSafeJSContext;

    return mSafeJSContext;
}
예제 #2
0
JSContext*
XPCJSContextStack::InitSafeJSContext()
{
    MOZ_ASSERT(!mSafeJSContext);

    // Start by getting the principal holder and principal for this
    // context.  If we can't manage that, don't bother with the rest.
    nsRefPtr<nsNullPrincipal> principal = new nsNullPrincipal();
    nsresult rv = principal->Init();
    if (NS_FAILED(rv))
        MOZ_CRASH();

    nsXPConnect* xpc = nsXPConnect::XPConnect();
    JSRuntime *rt = xpc->GetRuntime()->Runtime();
    if (!rt)
        MOZ_CRASH();

    mSafeJSContext = JS_NewContext(rt, 8192);
    if (!mSafeJSContext)
        MOZ_CRASH();
    JSAutoRequest req(mSafeJSContext);
    ContextOptionsRef(mSafeJSContext).setNoDefaultCompartmentObject(true);

    JS_SetErrorReporter(mSafeJSContext, xpc::SystemErrorReporter);

    JS::CompartmentOptions options;
    options.setZone(JS::SystemZone)
           .setTrace(TraceXPCGlobal);
    mSafeJSContextGlobal = CreateGlobalObject(mSafeJSContext,
                                              &SafeJSContextGlobalClass,
                                              principal, options);
    if (!mSafeJSContextGlobal)
        MOZ_CRASH();
    JS_AddNamedObjectRoot(mSafeJSContext, &mSafeJSContextGlobal, "SafeJSContext global");

    // Note: make sure to set the private before calling
    // InitClasses
    nsRefPtr<SandboxPrivate> sp = new SandboxPrivate(principal, mSafeJSContextGlobal);
    JS_SetPrivate(mSafeJSContextGlobal, sp.forget().take());

    // After this point either glob is null and the
    // nsIScriptObjectPrincipal ownership is either handled by the
    // nsCOMPtr or dealt with, or we'll release in the finalize
    // hook.
    if (NS_FAILED(xpc->InitClasses(mSafeJSContext, mSafeJSContextGlobal)))
        MOZ_CRASH();

    JS::RootedObject glob(mSafeJSContext, mSafeJSContextGlobal);
    JS_FireOnNewGlobalObject(mSafeJSContext, glob);

    return mSafeJSContext;
}
예제 #3
0
JSContext*
XPCJSContextStack::InitSafeJSContext()
{
    MOZ_ASSERT(!mSafeJSContext);

    // Start by getting the principal holder and principal for this
    // context.  If we can't manage that, don't bother with the rest.
    nsRefPtr<nsNullPrincipal> principal = new nsNullPrincipal();
    nsresult rv = principal->Init();
    if (NS_FAILED(rv))
        MOZ_CRASH();

    nsXPConnect* xpc = nsXPConnect::XPConnect();
    JSRuntime *rt = xpc->GetRuntime()->Runtime();
    if (!rt)
        MOZ_CRASH();

    mSafeJSContext = JS_NewContext(rt, 8192);
    if (!mSafeJSContext)
        MOZ_CRASH();
    JSAutoRequest req(mSafeJSContext);
    ContextOptionsRef(mSafeJSContext).setNoDefaultCompartmentObject(true);

    JS_SetErrorReporter(mSafeJSContext, xpc::SystemErrorReporter);

    // Note - We intentionally avoid firing OnNewGlobalObject while
    // simultaneously skipping the call to setInvisibleToDebugger(true) here.
    // This lets us piggy-back on the assertions in the JS engine (which make
    // sure that, for non-invisible globals, we always fire onNewGlobalObject
    // before creating scripts), to assert that we never create scripts with
    // the SafeJSContextGlobal. This is all happening way before anyone could be
    // listening for debugger notifications anyway.
    JS::CompartmentOptions options;
    options.setZone(JS::SystemZone)
           .setTrace(TraceXPCGlobal);
    mSafeJSContextGlobal = CreateGlobalObject(mSafeJSContext,
                                              &SafeJSContextGlobalClass,
                                              principal, options);
    if (!mSafeJSContextGlobal)
        MOZ_CRASH();

    nsRefPtr<SandboxPrivate> sp = new SandboxPrivate(principal, mSafeJSContextGlobal);
    JS_SetPrivate(mSafeJSContextGlobal, sp.forget().take());
    return mSafeJSContext;
}
예제 #4
0
GlobalObject *
JSRuntime::createSelfHostingGlobal(JSContext *cx)
{
    MOZ_ASSERT(!cx->isExceptionPending());
    MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));

    JS::CompartmentOptions options;
    options.setDiscardSource(true);
    options.setZone(JS::FreshZone);

    JSCompartment *compartment = NewCompartment(cx, nullptr, nullptr, options);
    if (!compartment)
        return nullptr;

    static const Class shgClass = {
        "self-hosting-global", JSCLASS_GLOBAL_FLAGS,
        nullptr, nullptr, nullptr, nullptr,
        nullptr, nullptr, nullptr, nullptr,
        nullptr, nullptr, nullptr,
        JS_GlobalObjectTraceHook
    };

    AutoCompartment ac(cx, compartment);
    Rooted<GlobalObject*> shg(cx, GlobalObject::createInternal(cx, &shgClass));
    if (!shg)
        return nullptr;

    cx->runtime()->selfHostingGlobal_ = shg;
    compartment->isSelfHosting = true;
    compartment->isSystem = true;

    if (!GlobalObject::initSelfHostingBuiltins(cx, shg, intrinsic_functions))
        return nullptr;

    JS_FireOnNewGlobalObject(cx, shg);

    return shg;
}
예제 #5
0
  nsresult Init()
  {
    mRuntime = JS_NewRuntime(sRuntimeHeapSize, JS_NO_HELPER_THREADS);
    NS_ENSURE_TRUE(mRuntime, NS_ERROR_OUT_OF_MEMORY);

    /*
     * Not setting this will cause JS_CHECK_RECURSION to report false
     * positives
     */
    JS_SetNativeStackQuota(mRuntime, 128 * sizeof(size_t) * 1024); 

    mContext = JS_NewContext(mRuntime, 0);
    NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY);

    JSAutoRequest ar(mContext);

    JS::CompartmentOptions options;
    options.setZone(JS::SystemZone)
           .setVersion(JSVERSION_LATEST);
    mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr,
                                 JS::DontFireOnNewGlobalHook, options);
    NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY);
    JS::Rooted<JSObject*> global(mContext, mGlobal);

    JSAutoCompartment ac(mContext, global);
    js::SetDefaultObjectForContext(mContext, global);
    JS_InitStandardClasses(mContext, global);

    JS_SetErrorReporter(mContext, PACErrorReporter);

    if (!JS_DefineFunctions(mContext, global, PACGlobalFunctions))
      return NS_ERROR_FAILURE;

    JS_FireOnNewGlobalObject(mContext, global);

    return NS_OK;
  }
예제 #6
0
bool
XPCShellEnvironment::Init()
{
    nsresult rv;

    // unbuffer stdout so that output is in the correct order; note that stderr
    // is unbuffered by default
    setbuf(stdout, 0);

    nsCOMPtr<nsIJSRuntimeService> rtsvc =
        do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
    if (!rtsvc) {
        NS_ERROR("failed to get nsJSRuntimeService!");
        return false;
    }

    JSRuntime *rt;
    if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
        NS_ERROR("failed to get JSRuntime from nsJSRuntimeService!");
        return false;
    }

    if (!mGlobalHolder.Hold(rt)) {
        NS_ERROR("Can't protect global object!");
        return false;
    }

    AutoSafeJSContext cx;

    JS_SetContextPrivate(cx, this);

    nsCOMPtr<nsIXPConnect> xpc =
      do_GetService(nsIXPConnect::GetCID());
    if (!xpc) {
        NS_ERROR("failed to get nsXPConnect service!");
        return false;
    }

    nsCOMPtr<nsIPrincipal> principal;
    nsCOMPtr<nsIScriptSecurityManager> securityManager =
        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
    if (NS_SUCCEEDED(rv) && securityManager) {
        rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
        if (NS_FAILED(rv)) {
            fprintf(stderr, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
        }
    } else {
        fprintf(stderr, "+++ Failed to get ScriptSecurityManager service, running without principals");
    }

    nsRefPtr<BackstagePass> backstagePass;
    rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
    if (NS_FAILED(rv)) {
        NS_ERROR("Failed to create backstage pass!");
        return false;
    }

    JS::CompartmentOptions options;
    options.setZone(JS::SystemZone)
           .setVersion(JSVERSION_LATEST);
    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
    rv = xpc->InitClassesWithNewWrappedGlobal(cx,
                                              static_cast<nsIGlobalObject *>(backstagePass),
                                              principal, 0,
                                              options,
                                              getter_AddRefs(holder));
    if (NS_FAILED(rv)) {
        NS_ERROR("InitClassesWithNewWrappedGlobal failed!");
        return false;
    }

    JS::Rooted<JSObject*> globalObj(cx, holder->GetJSObject());
    if (!globalObj) {
        NS_ERROR("Failed to get global JSObject!");
        return false;
    }
    JSAutoCompartment ac(cx, globalObj);

    backstagePass->SetGlobalObject(globalObj);

    if (!JS_DefineProperty(cx, globalObj, "__XPCShellEnvironment",
                           PRIVATE_TO_JSVAL(this), JS_PropertyStub,
                           JS_StrictPropertyStub,
                           JSPROP_READONLY | JSPROP_PERMANENT) ||
        !JS_DefineFunctions(cx, globalObj, gGlobalFunctions) ||
        !JS_DefineProfilingFunctions(cx, globalObj))
    {
        NS_ERROR("JS_DefineFunctions failed!");
        return false;
    }

    mGlobalHolder = globalObj;

    FILE* runtimeScriptFile = fopen(kDefaultRuntimeScriptFilename, "r");
    if (runtimeScriptFile) {
        fprintf(stdout, "[loading '%s'...]\n", kDefaultRuntimeScriptFilename);
        ProcessFile(cx, globalObj, kDefaultRuntimeScriptFilename,
                    runtimeScriptFile, false);
        fclose(runtimeScriptFile);
    }

    return true;
}
예제 #7
0
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;
}
예제 #8
0
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;
}
bool
XPCShellEnvironment::Init()
{
    nsresult rv;

#ifdef HAVE_SETBUF
    // unbuffer stdout so that output is in the correct order; note that stderr
    // is unbuffered by default
    setbuf(stdout, 0);
#endif

    nsCOMPtr<nsIJSRuntimeService> rtsvc =
        do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
    if (!rtsvc) {
        NS_ERROR("failed to get nsJSRuntimeService!");
        return false;
    }

    JSRuntime *rt;
    if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
        NS_ERROR("failed to get JSRuntime from nsJSRuntimeService!");
        return false;
    }

    if (!mGlobalHolder.Hold(rt)) {
        NS_ERROR("Can't protect global object!");
        return false;
    }

    gOldContextCallback = JS_SetContextCallback(rt, ContextCallback);

    JSContext *cx = JS_NewContext(rt, 8192);
    if (!cx) {
        NS_ERROR("JS_NewContext failed!");

        JS_SetContextCallback(rt, gOldContextCallback);
        gOldContextCallback = NULL;

        return false;
    }
    mCx = cx;

    JS_SetContextPrivate(cx, this);

    nsCOMPtr<nsIXPConnect> xpc =
      do_GetService(nsIXPConnect::GetCID());
    if (!xpc) {
        NS_ERROR("failed to get nsXPConnect service!");
        return false;
    }

    nsCOMPtr<nsIPrincipal> principal;
    nsCOMPtr<nsIScriptSecurityManager> securityManager =
        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
    if (NS_SUCCEEDED(rv) && securityManager) {
        rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
        if (NS_FAILED(rv)) {
            fprintf(stderr, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
        } else {
            // fetch the JS principals and stick in a global
            mJSPrincipals = nsJSPrincipals::get(principal);
            JS_HoldPrincipals(mJSPrincipals);
        }
    } else {
        fprintf(stderr, "+++ Failed to get ScriptSecurityManager service, running without principals");
    }

    nsCxPusher pusher;
    pusher.Push(mCx);

    nsRefPtr<BackstagePass> backstagePass;
    rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
    if (NS_FAILED(rv)) {
        NS_ERROR("Failed to create backstage pass!");
        return false;
    }

    JS::CompartmentOptions options;
    options.setZone(JS::SystemZone)
           .setVersion(JSVERSION_LATEST);
    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
    rv = xpc->InitClassesWithNewWrappedGlobal(cx,
                                              static_cast<nsIGlobalObject *>(backstagePass),
                                              principal, 0,
                                              options,
                                              getter_AddRefs(holder));
    if (NS_FAILED(rv)) {
        NS_ERROR("InitClassesWithNewWrappedGlobal failed!");
        return false;
    }

    JS::Rooted<JSObject*> globalObj(cx, holder->GetJSObject());
    if (!globalObj) {
        NS_ERROR("Failed to get global JSObject!");
        return false;
    }

    backstagePass->SetGlobalObject(globalObj);

    {
        JSAutoRequest ar(cx);
        JSAutoCompartment ac(cx, globalObj);

        if (!JS_DefineFunctions(cx, globalObj, gGlobalFunctions) ||
	    !JS_DefineProfilingFunctions(cx, globalObj)) {
            NS_ERROR("JS_DefineFunctions failed!");
            return false;
        }
    }

    mGlobalHolder = globalObj;

    FILE* runtimeScriptFile = fopen(kDefaultRuntimeScriptFilename, "r");
    if (runtimeScriptFile) {
        fprintf(stdout, "[loading '%s'...]\n", kDefaultRuntimeScriptFilename);
        ProcessFile(cx, globalObj, kDefaultRuntimeScriptFilename,
                    runtimeScriptFile, JS_FALSE);
        fclose(runtimeScriptFile);
    }

    return true;
}