| File: | root/firefox-clang/browser/app/nsBrowserApp.cpp |
| Warning: | line 180, column 15 Potential memory leak |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||||
| 2 | /* This Source Code Form is subject to the terms of the Mozilla Public | ||||
| 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
| 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
| 5 | |||||
| 6 | #include "nsXULAppAPI.h" | ||||
| 7 | #include "mozilla/XREAppData.h" | ||||
| 8 | #include "XREChildData.h" | ||||
| 9 | #include "XREShellData.h" | ||||
| 10 | #include "application.ini.h" | ||||
| 11 | #include "mozilla/Bootstrap.h" | ||||
| 12 | #include "mozilla/ProcessType.h" | ||||
| 13 | #include "mozilla/RuntimeExceptionModule.h" | ||||
| 14 | #include "mozilla/ScopeExit.h" | ||||
| 15 | #include "BrowserDefines.h" | ||||
| 16 | #if defined(XP_WIN) | ||||
| 17 | # include <windows.h> | ||||
| 18 | # include <stdlib.h> | ||||
| 19 | #elif defined(XP_UNIX1) | ||||
| 20 | # include <sys/resource.h> | ||||
| 21 | # include <unistd.h> | ||||
| 22 | # include <fcntl.h> | ||||
| 23 | #endif | ||||
| 24 | |||||
| 25 | #include <stdio.h> | ||||
| 26 | #include <stdarg.h> | ||||
| 27 | #include <time.h> | ||||
| 28 | |||||
| 29 | #include "nsCOMPtr.h" | ||||
| 30 | |||||
| 31 | #ifdef XP_WIN | ||||
| 32 | # include "mozilla/PreXULSkeletonUI.h" | ||||
| 33 | # include "freestanding/SharedSection.h" | ||||
| 34 | # include "LauncherProcessWin.h" | ||||
| 35 | # include "mozilla/GeckoArgs.h" | ||||
| 36 | # include "mozilla/mscom/ProcessRuntime.h" | ||||
| 37 | # include "mozilla/WindowsDllBlocklist.h" | ||||
| 38 | # include "mozilla/WindowsDpiInitialization.h" | ||||
| 39 | # include "mozilla/WindowsProcessMitigations.h" | ||||
| 40 | |||||
| 41 | # define XRE_WANT_ENVIRON | ||||
| 42 | # include "nsWindowsWMain.cpp" | ||||
| 43 | |||||
| 44 | # define strcasecmp _stricmp | ||||
| 45 | # ifdef MOZ_SANDBOX1 | ||||
| 46 | # include "mozilla/sandboxing/SandboxInitialization.h" | ||||
| 47 | # include "mozilla/sandboxing/sandboxLogging.h" | ||||
| 48 | # endif | ||||
| 49 | #endif | ||||
| 50 | #include "BinaryPath.h" | ||||
| 51 | |||||
| 52 | #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL | ||||
| 53 | |||||
| 54 | #include "mozilla/Sprintf.h" | ||||
| 55 | #include "mozilla/StartupTimeline.h" | ||||
| 56 | #include "BaseProfiler.h" | ||||
| 57 | |||||
| 58 | #ifdef LIBFUZZER | ||||
| 59 | # include "FuzzerDefs.h" | ||||
| 60 | #endif | ||||
| 61 | |||||
| 62 | #ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR | ||||
| 63 | # include <cpuid.h> | ||||
| 64 | # include "mozilla/Unused.h" | ||||
| 65 | |||||
| 66 | static bool IsSSE2Available() { | ||||
| 67 | // The rest of the app has been compiled to assume that SSE2 is present | ||||
| 68 | // unconditionally, so we can't use the normal copy of SSE.cpp here. | ||||
| 69 | // Since SSE.cpp caches the results and we need them only transiently, | ||||
| 70 | // instead of #including SSE.cpp here, let's just inline the specific check | ||||
| 71 | // that's needed. | ||||
| 72 | unsigned int level = 1u; | ||||
| 73 | unsigned int eax, ebx, ecx, edx; | ||||
| 74 | unsigned int bits = (1u << 26); | ||||
| 75 | unsigned int max = __get_cpuid_max(0, nullptr); | ||||
| 76 | if (level > max) { | ||||
| 77 | return false; | ||||
| 78 | } | ||||
| 79 | __cpuid_count(level, 0, eax, ebx, ecx, edx); | ||||
| 80 | return (edx & bits) == bits; | ||||
| 81 | } | ||||
| 82 | |||||
| 83 | static const char sSSE2Message[] = | ||||
| 84 | "This browser version requires a processor with the SSE2 instruction " | ||||
| 85 | "set extension.\nYou may be able to obtain a version that does not " | ||||
| 86 | "require SSE2 from your Linux distribution.\n"; | ||||
| 87 | |||||
| 88 | __attribute__((constructor)) static void SSE2Check() { | ||||
| 89 | if (IsSSE2Available()) { | ||||
| 90 | return; | ||||
| 91 | } | ||||
| 92 | // Using write() in order to avoid jemalloc-based buffering. Ignoring return | ||||
| 93 | // values, since there isn't much we could do on failure and there is no | ||||
| 94 | // point in trying to recover from errors. | ||||
| 95 | MOZ_UNUSED(write(STDERR_FILENO, sSSE2Message, std::size(sSSE2Message) - 1))do { if (write(2, sSSE2Message, std::size(sSSE2Message) - 1)) { (void)0; } } while (0); | ||||
| 96 | // _exit() instead of exit() to avoid running the usual "at exit" code. | ||||
| 97 | _exit(255); | ||||
| 98 | } | ||||
| 99 | #endif | ||||
| 100 | |||||
| 101 | #if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID) | ||||
| 102 | # define MOZ_BROWSER_CAN_BE_CONTENTPROC | ||||
| 103 | #endif | ||||
| 104 | |||||
| 105 | using namespace mozilla; | ||||
| 106 | |||||
| 107 | #ifdef XP_MACOSX | ||||
| 108 | # define kOSXResourcesFolder "Resources" | ||||
| 109 | #endif | ||||
| 110 | #define kDesktopFolder"browser" "browser" | ||||
| 111 | |||||
| 112 | static MOZ_FORMAT_PRINTF(1, 2)__attribute__((format(printf, 1, 2))) void Output(const char* fmt, ...) { | ||||
| 113 | va_list ap; | ||||
| 114 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | ||||
| 115 | |||||
| 116 | #ifndef XP_WIN | ||||
| 117 | vfprintf(stderrstderr, fmt, ap); | ||||
| 118 | #else | ||||
| 119 | char msg[2048]; | ||||
| 120 | vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap); | ||||
| 121 | |||||
| 122 | wchar_t wide_msg[2048]; | ||||
| 123 | MultiByteToWideChar(CP_UTF8, 0, msg, -1, wide_msg, _countof(wide_msg)); | ||||
| 124 | # if MOZ_WINCONSOLE | ||||
| 125 | fwprintf_s(stderrstderr, wide_msg); | ||||
| 126 | # else | ||||
| 127 | // Linking user32 at load-time interferes with the DLL blocklist (bug 932100). | ||||
| 128 | // This is a rare codepath, so we can load user32 at run-time instead. | ||||
| 129 | HMODULE user32 = LoadLibraryW(L"user32.dll"); | ||||
| 130 | if (user32) { | ||||
| 131 | decltype(MessageBoxW)* messageBoxW = | ||||
| 132 | (decltype(MessageBoxW)*)GetProcAddress(user32, "MessageBoxW"); | ||||
| 133 | if (messageBoxW) { | ||||
| 134 | messageBoxW(nullptr, wide_msg, L"Firefox", | ||||
| 135 | MB_OK | MB_ICONERROR | MB_SETFOREGROUND); | ||||
| 136 | } | ||||
| 137 | FreeLibrary(user32); | ||||
| 138 | } | ||||
| 139 | # endif | ||||
| 140 | #endif | ||||
| 141 | |||||
| 142 | va_end(ap)__builtin_va_end(ap); | ||||
| 143 | } | ||||
| 144 | |||||
| 145 | /** | ||||
| 146 | * Return true if |arg| matches the given argument name. | ||||
| 147 | */ | ||||
| 148 | static bool IsArg(const char* arg, const char* s) { | ||||
| 149 | if (*arg == '-') { | ||||
| 150 | if (*++arg == '-') ++arg; | ||||
| 151 | return !strcasecmp(arg, s); | ||||
| 152 | } | ||||
| 153 | |||||
| 154 | #if defined(XP_WIN) | ||||
| 155 | if (*arg == '/') return !strcasecmp(++arg, s); | ||||
| 156 | #endif | ||||
| 157 | |||||
| 158 | return false; | ||||
| 159 | } | ||||
| 160 | |||||
| 161 | MOZ_RUNINIT Bootstrap::UniquePtr gBootstrap; | ||||
| 162 | |||||
| 163 | static int do_main(int argc, char* argv[], char* envp[]) { | ||||
| 164 | // Allow firefox.exe to launch XULRunner apps via -app <application.ini> | ||||
| 165 | // Note that -app must be the *first* argument. | ||||
| 166 | const char* appDataFile = getenv("XUL_APP_FILE"); | ||||
| 167 | if ((!appDataFile
| ||||
| 168 | if (argc == 2) { | ||||
| 169 | Output("Incorrect number of arguments passed to -app"); | ||||
| 170 | return 255; | ||||
| 171 | } | ||||
| 172 | appDataFile = argv[2]; | ||||
| 173 | |||||
| 174 | char appEnv[MAXPATHLEN4096]; | ||||
| 175 | SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]); | ||||
| 176 | if (putenv(strdup(appEnv))) { | ||||
| 177 | Output("Couldn't set %s.\n", appEnv); | ||||
| 178 | return 255; | ||||
| 179 | } | ||||
| 180 | argv[2] = argv[0]; | ||||
| |||||
| 181 | argv += 2; | ||||
| 182 | argc -= 2; | ||||
| 183 | } else if (argc > 1 && IsArg(argv[1], "xpcshell")) { | ||||
| 184 | for (int i = 1; i < argc; i++) { | ||||
| 185 | argv[i] = argv[i + 1]; | ||||
| 186 | } | ||||
| 187 | |||||
| 188 | XREShellData shellData; | ||||
| 189 | #if defined(XP_WIN) && defined(MOZ_SANDBOX1) | ||||
| 190 | shellData.sandboxBrokerServices = | ||||
| 191 | sandboxing::GetInitializedBrokerServices(); | ||||
| 192 | #endif | ||||
| 193 | |||||
| 194 | #ifdef LIBFUZZER | ||||
| 195 | shellData.fuzzerDriver = fuzzer::FuzzerDriver; | ||||
| 196 | #endif | ||||
| 197 | #ifdef AFLFUZZ | ||||
| 198 | shellData.fuzzerDriver = afl_interface_raw; | ||||
| 199 | #endif | ||||
| 200 | |||||
| 201 | return gBootstrap->XRE_XPCShellMain(--argc, argv, envp, &shellData); | ||||
| 202 | } | ||||
| 203 | |||||
| 204 | BootstrapConfig config; | ||||
| 205 | |||||
| 206 | if (appDataFile && *appDataFile) { | ||||
| 207 | config.appData = nullptr; | ||||
| 208 | config.appDataPath = appDataFile; | ||||
| 209 | } else { | ||||
| 210 | // no -app flag so we use the compiled-in app data | ||||
| 211 | config.appData = &sAppData; | ||||
| 212 | config.appDataPath = kDesktopFolder"browser"; | ||||
| 213 | } | ||||
| 214 | |||||
| 215 | #if defined(XP_WIN) && defined(MOZ_SANDBOX1) | ||||
| 216 | sandbox::BrokerServices* brokerServices = | ||||
| 217 | sandboxing::GetInitializedBrokerServices(); | ||||
| 218 | if (!brokerServices) { | ||||
| 219 | Output("Couldn't initialize the broker services.\n"); | ||||
| 220 | return 255; | ||||
| 221 | } | ||||
| 222 | config.sandboxBrokerServices = brokerServices; | ||||
| 223 | #endif | ||||
| 224 | |||||
| 225 | #ifdef LIBFUZZER | ||||
| 226 | if (getenv("FUZZER")) | ||||
| 227 | gBootstrap->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver); | ||||
| 228 | #endif | ||||
| 229 | |||||
| 230 | EnsureBrowserCommandlineSafe(argc, argv); | ||||
| 231 | |||||
| 232 | return gBootstrap->XRE_main(argc, argv, config); | ||||
| 233 | } | ||||
| 234 | |||||
| 235 | static nsresult InitXPCOMGlue(LibLoadingStrategy aLibLoadingStrategy) { | ||||
| 236 | if (gBootstrap) { | ||||
| 237 | return NS_OK; | ||||
| 238 | } | ||||
| 239 | |||||
| 240 | UniqueFreePtr<char> exePath = BinaryPath::Get(); | ||||
| 241 | if (!exePath) { | ||||
| 242 | Output("Couldn't find the application directory.\n"); | ||||
| 243 | return NS_ERROR_FAILURE; | ||||
| 244 | } | ||||
| 245 | |||||
| 246 | auto bootstrapResult = | ||||
| 247 | mozilla::GetBootstrap(exePath.get(), aLibLoadingStrategy); | ||||
| 248 | if (bootstrapResult.isErr()) { | ||||
| 249 | Output("Couldn't load XPCOM.\n"); | ||||
| 250 | return NS_ERROR_FAILURE; | ||||
| 251 | } | ||||
| 252 | |||||
| 253 | gBootstrap = bootstrapResult.unwrap(); | ||||
| 254 | |||||
| 255 | // This will set this thread as the main thread. | ||||
| 256 | gBootstrap->NS_LogInit(); | ||||
| 257 | |||||
| 258 | return NS_OK; | ||||
| 259 | } | ||||
| 260 | |||||
| 261 | #ifdef HAS_DLL_BLOCKLIST | ||||
| 262 | // NB: This must be extern, as this value is checked elsewhere | ||||
| 263 | uint32_t gBlocklistInitFlags = eDllBlocklistInitFlagDefault; | ||||
| 264 | #endif | ||||
| 265 | |||||
| 266 | #if defined(XP_UNIX1) | ||||
| 267 | static void ReserveDefaultFileDescriptors() { | ||||
| 268 | // Reserve the lower positions of the file descriptors to make sure | ||||
| 269 | // we don't reuse stdin/stdout/stderr in case they were closed | ||||
| 270 | // before launch. | ||||
| 271 | // Otherwise code explicitly writing to fd 1 or 2 might accidentally | ||||
| 272 | // write to something else, like in bug 1820896 where FD 1 is | ||||
| 273 | // reused for the X server display connection. | ||||
| 274 | int fd = open("/dev/null", O_RDONLY00); | ||||
| 275 | for (int i = 0; i < 2; i++) { | ||||
| 276 | mozilla::Unused << dup(fd); | ||||
| 277 | } | ||||
| 278 | } | ||||
| 279 | #endif | ||||
| 280 | |||||
| 281 | int main(int argc, char* argv[], char* envp[]) { | ||||
| 282 | #if defined(XP_UNIX1) | ||||
| 283 | ReserveDefaultFileDescriptors(); | ||||
| 284 | #endif | ||||
| 285 | |||||
| 286 | #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC | ||||
| 287 | if (argc > 1 && IsArg(argv[1], "contentproc")) { | ||||
| |||||
| 288 | // Set the process type and gecko child id. | ||||
| 289 | SetGeckoProcessType(argv[--argc]); | ||||
| 290 | SetGeckoChildID(argv[--argc]); | ||||
| 291 | |||||
| 292 | # if defined(MOZ_ENABLE_FORKSERVER1) | ||||
| 293 | if (GetGeckoProcessType() == GeckoProcessType_ForkServer) { | ||||
| 294 | nsresult rv = InitXPCOMGlue(LibLoadingStrategy::NoReadAhead); | ||||
| 295 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | ||||
| 296 | return 255; | ||||
| 297 | } | ||||
| 298 | |||||
| 299 | // Run a fork server in this process, single thread. When it returns, it | ||||
| 300 | // means the fork server have been stopped or a new child process is | ||||
| 301 | // created. | ||||
| 302 | // | ||||
| 303 | // For the latter case, XRE_ForkServer() will return false, running in a | ||||
| 304 | // child process just forked from the fork server process. argc & argv | ||||
| 305 | // will be updated with the values passing from the chrome process, as | ||||
| 306 | // will GeckoProcessType and GeckoChildID. With the new values, this | ||||
| 307 | // function continues the reset of the code acting as a child process. | ||||
| 308 | if (gBootstrap->XRE_ForkServer(&argc, &argv)) { | ||||
| 309 | // Return from the fork server in the fork server process. | ||||
| 310 | // Stop the fork server. | ||||
| 311 | // InitXPCOMGlue calls NS_LogInit, so we need to balance it here. | ||||
| 312 | gBootstrap->NS_LogTerm(); | ||||
| 313 | return 0; | ||||
| 314 | } | ||||
| 315 | } | ||||
| 316 | # endif | ||||
| 317 | } | ||||
| 318 | #endif | ||||
| 319 | |||||
| 320 | mozilla::TimeStamp start = mozilla::TimeStamp::Now(); | ||||
| 321 | |||||
| 322 | AUTO_BASE_PROFILER_INIT::mozilla::baseprofiler::AutoProfilerInit raiiObject322; | ||||
| 323 | AUTO_BASE_PROFILER_LABEL("nsBrowserApp main", OTHER)::mozilla::baseprofiler::AutoProfilerLabel raiiObject323( "nsBrowserApp main" , nullptr, ::mozilla::baseprofiler::ProfilingCategoryPair::OTHER ); | ||||
| 324 | |||||
| 325 | // Register an external module to report on otherwise uncatchable exceptions. | ||||
| 326 | // Note that in child processes this must be called after Gecko process type | ||||
| 327 | // has been set. | ||||
| 328 | CrashReporter::RegisterRuntimeExceptionModule(); | ||||
| 329 | |||||
| 330 | // Make sure we unregister the runtime exception module before returning. | ||||
| 331 | auto unregisterRuntimeExceptionModule = | ||||
| 332 | MakeScopeExit([] { CrashReporter::UnregisterRuntimeExceptionModule(); }); | ||||
| 333 | |||||
| 334 | #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC | ||||
| 335 | // We are launching as a content process, delegate to the appropriate | ||||
| 336 | // main | ||||
| 337 | if (GetGeckoProcessType() != GeckoProcessType_Default) { | ||||
| 338 | # if defined(XP_WIN) && defined(MOZ_SANDBOX1) | ||||
| 339 | // We need to set whether our process is supposed to have win32k locked down | ||||
| 340 | // from the command line setting before DllBlocklist_Initialize, | ||||
| 341 | // GetInitializedTargetServices and WindowsDpiInitialization. | ||||
| 342 | Maybe<bool> win32kLockedDown = | ||||
| 343 | mozilla::geckoargs::sWin32kLockedDown.Get(argc, argv); | ||||
| 344 | if (win32kLockedDown.isSome() && *win32kLockedDown) { | ||||
| 345 | mozilla::SetWin32kLockedDownInPolicy(); | ||||
| 346 | } | ||||
| 347 | # endif | ||||
| 348 | |||||
| 349 | # ifdef HAS_DLL_BLOCKLIST | ||||
| 350 | uint32_t initFlags = | ||||
| 351 | gBlocklistInitFlags | eDllBlocklistInitFlagIsChildProcess; | ||||
| 352 | SetDllBlocklistProcessTypeFlags(initFlags, GetGeckoProcessType()); | ||||
| 353 | DllBlocklist_Initialize(initFlags); | ||||
| 354 | # endif // HAS_DLL_BLOCKLIST | ||||
| 355 | |||||
| 356 | # if defined(XP_WIN) && defined(MOZ_SANDBOX1) | ||||
| 357 | // We need to initialize the sandbox TargetServices before InitXPCOMGlue | ||||
| 358 | // because we might need the sandbox broker to give access to some files. | ||||
| 359 | if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) { | ||||
| 360 | Output("Failed to initialize the sandbox target services."); | ||||
| 361 | return 255; | ||||
| 362 | } | ||||
| 363 | # endif | ||||
| 364 | # if defined(XP_WIN) | ||||
| 365 | // Ideally, we would be able to set our DPI awareness in | ||||
| 366 | // firefox.exe.manifest Unfortunately, that would cause Win32k calls when | ||||
| 367 | // user32.dll gets loaded, which would be incompatible with Win32k Lockdown | ||||
| 368 | // | ||||
| 369 | // MSDN says that it's allowed-but-not-recommended to initialize DPI | ||||
| 370 | // programatically, as long as it's done before any HWNDs are created. | ||||
| 371 | // Thus, we do it almost as soon as we possibly can | ||||
| 372 | { | ||||
| 373 | auto result = mozilla::WindowsDpiInitialization(); | ||||
| 374 | (void)result; // Ignore errors since some tools block DPI calls | ||||
| 375 | } | ||||
| 376 | # endif | ||||
| 377 | |||||
| 378 | nsresult rv = InitXPCOMGlue(LibLoadingStrategy::NoReadAhead); | ||||
| 379 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | ||||
| 380 | return 255; | ||||
| 381 | } | ||||
| 382 | |||||
| 383 | XREChildData childData; | ||||
| 384 | |||||
| 385 | # if defined(XP_WIN) && defined(MOZ_SANDBOX1) | ||||
| 386 | if (IsSandboxedProcess()) { | ||||
| 387 | childData.sandboxTargetServices = | ||||
| 388 | mozilla::sandboxing::GetInitializedTargetServices(); | ||||
| 389 | if (!childData.sandboxTargetServices) { | ||||
| 390 | return 1; | ||||
| 391 | } | ||||
| 392 | |||||
| 393 | childData.ProvideLogFunction = mozilla::sandboxing::ProvideLogFunction; | ||||
| 394 | } | ||||
| 395 | # endif | ||||
| 396 | |||||
| 397 | rv = gBootstrap->XRE_InitChildProcess(argc, argv, &childData); | ||||
| 398 | |||||
| 399 | # if defined(DEBUG1) && defined(HAS_DLL_BLOCKLIST) | ||||
| 400 | DllBlocklist_Shutdown(); | ||||
| 401 | # endif | ||||
| 402 | |||||
| 403 | // InitXPCOMGlue calls NS_LogInit, so we need to balance it here. | ||||
| 404 | gBootstrap->NS_LogTerm(); | ||||
| 405 | |||||
| 406 | return NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) ? 1 : 0; | ||||
| 407 | } | ||||
| 408 | #endif | ||||
| 409 | |||||
| 410 | #ifdef HAS_DLL_BLOCKLIST | ||||
| 411 | DllBlocklist_Initialize(gBlocklistInitFlags); | ||||
| 412 | #endif | ||||
| 413 | |||||
| 414 | // We will likely only ever support this as a command line argument on Windows | ||||
| 415 | // and OSX, so we're ifdefing here just to not create any expectations. | ||||
| 416 | #if defined(XP_WIN) || defined(XP_MACOSX) | ||||
| 417 | if (argc > 1 && IsArg(argv[1], "silentmode")) { | ||||
| 418 | ::putenv(const_cast<char*>("MOZ_APP_SILENT_START=1")); | ||||
| 419 | # if defined(XP_WIN) | ||||
| 420 | // On windows We also want to set a separate variable, which we want to | ||||
| 421 | // persist across restarts, which will let us keep the process alive | ||||
| 422 | // even if the last window is closed. | ||||
| 423 | ::putenv(const_cast<char*>("MOZ_APP_ALLOW_WINDOWLESS=1")); | ||||
| 424 | # endif | ||||
| 425 | # if defined(XP_MACOSX) | ||||
| 426 | ::putenv(const_cast<char*>("MOZ_APP_NO_DOCK=1")); | ||||
| 427 | # endif | ||||
| 428 | } | ||||
| 429 | #endif | ||||
| 430 | |||||
| 431 | #if defined(XP_WIN) | ||||
| 432 | |||||
| 433 | // Ideally, we would be able to set our DPI awareness in firefox.exe.manifest | ||||
| 434 | // Unfortunately, that would cause Win32k calls when user32.dll gets loaded, | ||||
| 435 | // which would be incompatible with Win32k Lockdown | ||||
| 436 | // | ||||
| 437 | // MSDN says that it's allowed-but-not-recommended to initialize DPI | ||||
| 438 | // programatically, as long as it's done before any HWNDs are created. | ||||
| 439 | // Thus, we do it almost as soon as we possibly can | ||||
| 440 | { | ||||
| 441 | auto result = mozilla::WindowsDpiInitialization(); | ||||
| 442 | (void)result; // Ignore errors since some tools block DPI calls | ||||
| 443 | } | ||||
| 444 | |||||
| 445 | // Once the browser process hits the main function, we no longer need | ||||
| 446 | // a writable section handle because all dependent modules have been | ||||
| 447 | // loaded. | ||||
| 448 | mozilla::freestanding::gSharedSection.ConvertToReadOnly(); | ||||
| 449 | |||||
| 450 | mozilla::CreateAndStorePreXULSkeletonUI(GetModuleHandle(nullptr), argc, argv); | ||||
| 451 | #endif | ||||
| 452 | |||||
| 453 | nsresult rv = InitXPCOMGlue(LibLoadingStrategy::ReadAhead); | ||||
| 454 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | ||||
| 455 | return 255; | ||||
| 456 | } | ||||
| 457 | |||||
| 458 | gBootstrap->XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start); | ||||
| 459 | |||||
| 460 | #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC | ||||
| 461 | gBootstrap->XRE_EnableSameExecutableForContentProc(); | ||||
| 462 | #endif | ||||
| 463 | |||||
| 464 | int result = do_main(argc, argv, envp); | ||||
| 465 | |||||
| 466 | #if defined(XP_WIN) | ||||
| 467 | CleanupProcessRuntime(); | ||||
| 468 | #endif | ||||
| 469 | |||||
| 470 | gBootstrap->NS_LogTerm(); | ||||
| 471 | |||||
| 472 | #if defined(DEBUG1) && defined(HAS_DLL_BLOCKLIST) | ||||
| 473 | DllBlocklist_Shutdown(); | ||||
| 474 | #endif | ||||
| 475 | |||||
| 476 | #ifdef XP_MACOSX | ||||
| 477 | // Allow writes again. While we would like to catch writes from static | ||||
| 478 | // destructors to allow early exits to use _exit, we know that there is | ||||
| 479 | // at least one such write that we don't control (see bug 826029). For | ||||
| 480 | // now we enable writes again and early exits will have to use exit instead | ||||
| 481 | // of _exit. | ||||
| 482 | gBootstrap->XRE_StopLateWriteChecks(); | ||||
| 483 | #endif | ||||
| 484 | |||||
| 485 | gBootstrap.reset(); | ||||
| 486 | |||||
| 487 | return result; | ||||
| 488 | } |