/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef ANDROID # include <android/log.h> # include "XREShellData.h" #endif
#ifdef MOZ_WIDGET_ANDROID # include "mozilla/java/GeckoThreadWrappers.h" #endif
#ifdef XP_WIN # include "mozilla/mscom/ProcessRuntime.h" # include "mozilla/ScopeExit.h" # include "mozilla/WinDllServices.h" # include "mozilla/WindowsBCryptInitialization.h" # include <windows.h> # ifdefined(MOZ_SANDBOX) # include "XREShellData.h" # include "sandboxBroker.h" # endif #endif
#ifdef MOZ_CODE_COVERAGE # include "mozilla/CodeCoverageHandler.h" #endif
// all this crap is needed to do the interactive shell stuff #include <stdlib.h> #include <errno.h> #ifdef HAVE_IO_H # include <io.h> /* for isatty() */ #endif #ifdef HAVE_UNISTD_H # include <unistd.h> /* for isatty() */ #endif
#ifdef ENABLE_TESTS # include "xpctest_private.h" #endif
// Fuzzing support for XPC runtime fuzzing #ifdef FUZZING_INTERFACES # include "xpcrtfuzzing/xpcrtfuzzing.h" # include "XREShellData.h"
MOZ_RUNINIT staticbool fuzzDoDebug = !!getenv("MOZ_FUZZ_DEBUG");
MOZ_RUNINIT staticbool fuzzHaveModule = !!getenv("FUZZER"); #endif// FUZZING_INTERFACES
using namespace mozilla;
using namespace JS;
using mozilla::dom::AutoEntryScript;
using mozilla::dom::AutoJSAPI;
class XPCShellDirProvider : public nsIDirectoryServiceProvider2 {
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDIRECTORYSERVICEPROVIDER
NS_DECL_NSIDIRECTORYSERVICEPROVIDER2
staticbool GetLocationProperty(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); if (!args.thisv().isObject()) {
JS_ReportErrorASCII(cx, "Unexpected this value for GetLocationProperty"); returnfalse;
} #if !defined(XP_WIN) && !defined(XP_UNIX) // XXX: your platform should really implement this returnfalse; #else
JS::AutoFilename filename; if (JS::DescribeScriptedCaller(&filename, cx) && filename.get()) {
NS_ConvertUTF8toUTF16 filenameString(filename.get());
# ifdefined(XP_WIN) // replace forward slashes with backslashes, // since nsLocalFileWin chokes on them
char16_t* start = filenameString.BeginWriting();
char16_t* end = filenameString.EndWriting();
while (start != end) { if (*start == L'/') {
*start = L'\\';
}
start++;
} # endif
if (!location && gWorkingDirectory) { // could be a relative path, try appending it to the cwd // and then normalize
nsAutoString absolutePath(*gWorkingDirectory);
absolutePath.Append(filenameString);
// While 4096 might be quite arbitrary, this is something to be fixed in // bug 105707. It is also the same limit as in ProcessFile. char buf[4096];
RootedString str(cx);
/* If a prompt was specified, construct the string */ if (args.length() > 0) {
str = JS::ToString(cx, args[0]); if (!str) { returnfalse;
}
} else {
str = JS_GetEmptyString(cx);
}
/* Get a line from the infile */
JS::UniqueChars strBytes = JS_EncodeStringToLatin1(cx, str); if (!strBytes || !GetLine(cx, buf, gInFile, strBytes.get())) { returnfalse;
}
/* Strip newline character added by GetLine() */ unsignedint buflen = strlen(buf); if (buflen == 0) { if (feof(gInFile)) {
args.rval().setNull(); return true;
}
} elseif (buf[buflen - 1] == '\n') {
--buflen;
}
/* Turn buf into a JSString */
str = JS_NewStringCopyN(cx, buf, buflen); if (!str) { returnfalse;
}
#ifdef FUZZING_INTERFACES if (fuzzHaveModule && !fuzzDoDebug) { // When fuzzing and not debugging, suppress any print() output, // as it slows down fuzzing and makes libFuzzer's output hard // to read. return true;
} #endif// FUZZING_INTERFACES
RootedString str(cx);
nsAutoCString utf8output;
for (unsigned i = 0; i < args.length(); i++) {
str = ToString(cx, args[i]); if (!str) { returnfalse;
}
JS::UniqueChars utf8str = JS_EncodeStringToUTF8(cx, str); if (!utf8str) { returnfalse;
}
JS::RootedObject thisObject(cx); if (!args.computeThis(cx, &thisObject)) { returnfalse;
} if (!JS_IsGlobalObject(thisObject)) {
JS_ReportErrorASCII(cx, "Trying to load() into a non-global object"); returnfalse;
}
RootedString str(cx); for (unsigned i = 0; i < args.length(); i++) {
str = ToString(cx, args[i]); if (!str) { returnfalse;
}
JS::UniqueChars filename = JS_EncodeStringToUTF8(cx, str); if (!filename) { returnfalse;
}
JS::CompileOptions options(cx);
options.setIsRunOnce(true).setSkipFilenameValidation(true);
JS::Rooted<JSScript*> script(
cx, JS::CompileUtf8Path(cx, options, filename.get())); if (!script) { returnfalse;
}
if (!compileOnly) { if (!JS_ExecuteScript(cx, script)) { returnfalse;
}
}
}
args.rval().setUndefined(); return true;
}
if (args.length() == 0) {
JS_ReportErrorASCII(cx, "Function takes at least one argument!"); returnfalse;
}
RootedString str(cx, ToString(cx, args[0])); if (!str) {
JS_ReportErrorASCII(cx, "Could not convert argument 1 to string!"); returnfalse;
}
if (args.get(1).isObject() && !JS_ObjectIsFunction(&args[1].toObject())) {
JS_ReportErrorASCII(cx, "Could not convert argument 2 to function!"); returnfalse;
}
// Sanity-check args.
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); if (args.length() != 1) {
JS_ReportErrorASCII(cx, "Wrong number of arguments"); returnfalse;
}
// Allow callers to remove the interrupt callback by passing undefined. if (args[0].isUndefined()) {
*sScriptedInterruptCallback = UndefinedValue(); return true;
}
// Otherwise, we should have a function object. if (!args[0].isObject() || !js::IsFunctionObject(&args[0].toObject())) {
JS_ReportErrorASCII(cx, "Argument must be a function"); returnfalse;
}
// This mimics mozilla::SpinEventLoopUntil but instead of spinning the // event loop we sleep, to make sure we don't run script.
xpc::AutoScriptActivity asa(false);
PR_Sleep(PR_SecondsToInterval(args[0].toInt32()));
args.rval().setUndefined(); return true;
}
#ifdef ANDROID staticbool ChangeTestShellDir(JSContext* cx, unsigned argc, Value* vp) { // This method should only be used by testing/xpcshell/head.js to change to // the correct directory on Android Remote XPCShell tests. // // TODO: Bug 1801725 - Find a more ergonomic way to do this than exposing // identical methods in XPCShellEnvironment and XPCShellImpl to chdir on // android for Remote XPCShell tests on Android.
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 1) {
JS_ReportErrorASCII(cx, "changeTestShellDir() takes one argument"); returnfalse;
}
nsAutoJSCString path; if (!path.init(cx, args[0])) {
JS_ReportErrorASCII(
cx, "changeTestShellDir(): could not convert argument 1 to string"); returnfalse;
}
if (chdir(path.get())) {
JS_ReportErrorASCII(cx, "changeTestShellDir(): could not change directory"); returnfalse;
}
staticbool GetCurrentWorkingDirectory(nsAString& workingDirectory) { #if !defined(XP_WIN) && !defined(XP_UNIX) // XXX: your platform should really implement this returnfalse; #elif XP_WIN
DWORD requiredLength = GetCurrentDirectoryW(0, nullptr);
workingDirectory.SetLength(requiredLength);
GetCurrentDirectoryW(workingDirectory.Length(),
(LPWSTR)workingDirectory.BeginWriting()); // we got a trailing null there
workingDirectory.SetLength(requiredLength);
workingDirectory.Replace(workingDirectory.Length() - 1, 1, L'\\'); #elifdefined(XP_UNIX)
nsAutoCString cwd; // 1024 is just a guess at a sane starting value
size_t bufsize = 1024; char* result = nullptr; while (result == nullptr) {
cwd.SetLength(bufsize);
result = getcwd(cwd.BeginWriting(), cwd.Length()); if (!result) { if (errno != ERANGE) { returnfalse;
} // need to make the buffer bigger
bufsize *= 2;
}
} // size back down to the actual string length
cwd.SetLength(strlen(result) + 1);
cwd.Replace(cwd.Length() - 1, 1, '/');
CopyUTF8toUTF16(cwd, workingDirectory); #endif return true;
}
// This guard ensures that all threads that attempt to register themselves // with the IOInterposer will be properly tracked.
mozilla::AutoIOInterposer ioInterposerGuard;
ioInterposerGuard.Init();
if (auto* featureStr = PR_GetEnv("MOZ_CHAOSMODE")) {
ChaosFeature feature = ChaosFeature::Any; long featureInt = strtol(featureStr, nullptr, 16); if (featureInt) { // NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
feature = static_cast<ChaosFeature>(featureInt);
}
ChaosMode::SetChaosFeature(feature);
ChaosMode::enterChaosMode();
MOZ_ASSERT(ChaosMode::isActive(ChaosFeature::Any));
}
if (ChaosMode::isActive(ChaosFeature::Any)) {
printf_stderr( "*** You are running in chaos test mode. See ChaosMode.h. ***\n");
}
#ifdef XP_WIN // Some COM settings are global to the process and must be set before any non- // trivial COM is run in the application. Since these settings may affect // stability, we should instantiate COM ASAP so that we can ensure that these // global settings are configured before anything can interfere.
mscom::ProcessRuntime mscom;
#ifdefined(XP_WIN) && defined(MOZ_SANDBOX) // We need the binary directory to initialize the windows sandbox.
MOZ_ALWAYS_SUCCEEDS(appDir->GetPath(binDirPath)); #endif
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"); return1;
}
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("Resources"_ns); bool dirExists = false;
tmpDir->Exists(&dirExists); if (dirExists) {
greDir = tmpDir.forget();
}
dirprovider.SetGREDirs(greDir); #else
nsAutoString workingDir; if (!GetCurrentWorkingDirectory(workingDir)) {
printf("GetCurrentWorkingDirectory failed.\n"); return1;
}
rv = NS_NewLocalFile(workingDir, getter_AddRefs(greDir)); if (NS_FAILED(rv)) {
printf("NS_NewLocalFile failed.\n"); return1;
} #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 = dir;
dirprovider.SetAppDir(appDir);
} if (NS_FAILED(rv)) {
printf("Couldn't use given appdir.\n"); return1;
}
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"); return1;
}
XRE_AddManifestLocation(NS_APP_LOCATION, lf);
argc -= 2;
argv += 2;
}
constchar* val = getenv("MOZ_CRASHREPORTER"); if (val && *val && !CrashReporter::IsDummy()) {
nsCOMPtr<nsIFile> greBinDir; bool persistent = false;
rv = dirprovider.GetFile(NS_GRE_BIN_DIR, &persistent,
getter_AddRefs(greBinDir)); if (NS_FAILED(rv)) {
printf("Could not get the GreBinD directory\n"); return1;
}
// Now that the profiler, directory services, and prefs have been // initialized we can find the download directory, where the profiler can // write profiles when user stops the profiler using POSIX signal handling.
profiler_lookup_async_signal_dump_directory();
// xpc::ErrorReport::LogToConsoleWithStack needs this to print errors // to stderr.
Preferences::SetBool("browser.dom.window.dump.enabled", true);
Preferences::SetBool("devtools.console.stdout.chrome", true);
AutoJSAPI jsapi;
jsapi.Init();
cx = jsapi.cx();
// 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 = new PersistentRootedValue;
sScriptedInterruptCallback->init(cx, UndefinedValue());
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(cx);
MOZ_ASSERT(
scb, "We are assuming that nsScriptSecurityManager::Init() has been run");
shellSecurityCallbacks = *scb;
JS_SetSecurityCallbacks(cx, &shellSecurityCallbacks);
auto systemGlobal = MakeRefPtr<SystemGlobal>();
// Make the default XPCShell global use a fresh zone (rather than the // System Zone) to improve cross-zone test coverage.
JS::RealmOptions options;
options.creationOptions().setNewCompartmentAndZone();
xpc::SetPrefableRealmOptions(options);
// 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.
options.behaviors().setDiscardSource(false);
// Initialize e10s check on the main thread, if not already done
BrowserTabsRemoteAutostart(); #ifdefined(XP_WIN) // Ensure that DLL Services are running
RefPtr<DllServices> dllSvc(DllServices::Get());
dllSvc->StartUntrustedModulesProcessor(true); auto dllServicesDisable =
MakeScopeExit([&dllSvc]() { dllSvc->DisableFull(); });
# ifdefined(MOZ_SANDBOX) // Required for sandboxed child processes. if (aShellData->sandboxBrokerServices) {
SandboxBroker::Initialize(aShellData->sandboxBrokerServices, binDirPath);
SandboxBroker::GeckoDependentInitialize();
} else {
NS_WARNING( "Failed to initialize broker services, sandboxed " "processes will fail to start.");
} # endif // defined(MOZ_SANDBOX)
{
DebugOnly<bool> result = WindowsBCryptInitialization();
MOZ_ASSERT(result);
} #endif// defined(XP_WIN)
{ #ifdef FUZZING_INTERFACES if (fuzzHaveModule) { // argv[0] was removed previously, but libFuzzer expects it
argc++;
argv--;
result = FuzzXPCRuntimeStart(&jsapi, &argc, &argv, aShellData);
} else { #endif // We are almost certainly going to run script here, so we need an // AutoEntryScript. This is Gecko-specific and not in any spec.
AutoEntryScript aes(systemGlobal, "xpcshell argument processing");
// If an exception is thrown, we'll set our return code // appropriately, and then let the AutoEntryScript destructor report // the error to the console. if (!ProcessArgs(aes, argv, argc, &dirprovider)) { if (gExitCode) {
result = gExitCode;
} elseif (gQuitting) {
result = 0;
} else {
result = EXITCODE_RUNTIME_ERROR;
}
} #ifdef FUZZING_INTERFACES
} #endif
}
// Signal that we're now shutting down.
nsCOMPtr<nsIObserver> obs = do_QueryInterface(appStartup); if (obs) {
obs->Observe(nullptr, "quit-application-forced", nullptr);
}
dirprovider.ClearGREDirs();
dirprovider.ClearAppDir();
dirprovider.ClearAppFile();
} // 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");
// Shut down the crashreporter service to prevent leaking some strings it // holds. if (CrashReporter::GetEnabled()) {
CrashReporter::UnsetExceptionHandler();
CrashReporter::OOPDeinit();
}
// This must precede NS_LogTerm(), otherwise xpcshell return non-zero // during some tests, which causes failures.
profiler_shutdown();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.