File: | var/lib/jenkins/workspace/firefox-scan-build/browser/app/nsBrowserApp.cpp |
Warning: | line 181, 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(do { if (write(2, sSSE2Message, sizeof(mozilla::detail::ArrayLengthHelper (sSSE2Message)) - 1)) { (void)0; } } while (0) | ||||
96 | write(STDERR_FILENO, sSSE2Message, MOZ_ARRAY_LENGTH(sSSE2Message) - 1))do { if (write(2, sSSE2Message, sizeof(mozilla::detail::ArrayLengthHelper (sSSE2Message)) - 1)) { (void)0; } } while (0); | ||||
97 | // _exit() instead of exit() to avoid running the usual "at exit" code. | ||||
98 | _exit(255); | ||||
99 | } | ||||
100 | #endif | ||||
101 | |||||
102 | #if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID) | ||||
103 | # define MOZ_BROWSER_CAN_BE_CONTENTPROC | ||||
104 | #endif | ||||
105 | |||||
106 | using namespace mozilla; | ||||
107 | |||||
108 | #ifdef XP_MACOSX | ||||
109 | # define kOSXResourcesFolder "Resources" | ||||
110 | #endif | ||||
111 | #define kDesktopFolder"browser" "browser" | ||||
112 | |||||
113 | static MOZ_FORMAT_PRINTF(1, 2)__attribute__((format(printf, 1, 2))) void Output(const char* fmt, ...) { | ||||
114 | va_list ap; | ||||
115 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | ||||
116 | |||||
117 | #ifndef XP_WIN | ||||
118 | vfprintf(stderrstderr, fmt, ap); | ||||
119 | #else | ||||
120 | char msg[2048]; | ||||
121 | vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap); | ||||
122 | |||||
123 | wchar_t wide_msg[2048]; | ||||
124 | MultiByteToWideChar(CP_UTF8, 0, msg, -1, wide_msg, _countof(wide_msg)); | ||||
125 | # if MOZ_WINCONSOLE | ||||
126 | fwprintf_s(stderrstderr, wide_msg); | ||||
127 | # else | ||||
128 | // Linking user32 at load-time interferes with the DLL blocklist (bug 932100). | ||||
129 | // This is a rare codepath, so we can load user32 at run-time instead. | ||||
130 | HMODULE user32 = LoadLibraryW(L"user32.dll"); | ||||
131 | if (user32) { | ||||
132 | decltype(MessageBoxW)* messageBoxW = | ||||
133 | (decltype(MessageBoxW)*)GetProcAddress(user32, "MessageBoxW"); | ||||
134 | if (messageBoxW) { | ||||
135 | messageBoxW(nullptr, wide_msg, L"Firefox", | ||||
136 | MB_OK | MB_ICONERROR | MB_SETFOREGROUND); | ||||
137 | } | ||||
138 | FreeLibrary(user32); | ||||
139 | } | ||||
140 | # endif | ||||
141 | #endif | ||||
142 | |||||
143 | va_end(ap)__builtin_va_end(ap); | ||||
144 | } | ||||
145 | |||||
146 | /** | ||||
147 | * Return true if |arg| matches the given argument name. | ||||
148 | */ | ||||
149 | static bool IsArg(const char* arg, const char* s) { | ||||
150 | if (*arg == '-') { | ||||
151 | if (*++arg == '-') ++arg; | ||||
152 | return !strcasecmp(arg, s); | ||||
153 | } | ||||
154 | |||||
155 | #if defined(XP_WIN) | ||||
156 | if (*arg == '/') return !strcasecmp(++arg, s); | ||||
157 | #endif | ||||
158 | |||||
159 | return false; | ||||
160 | } | ||||
161 | |||||
162 | Bootstrap::UniquePtr gBootstrap; | ||||
163 | |||||
164 | static int do_main(int argc, char* argv[], char* envp[]) { | ||||
165 | // Allow firefox.exe to launch XULRunner apps via -app <application.ini> | ||||
166 | // Note that -app must be the *first* argument. | ||||
167 | const char* appDataFile = getenv("XUL_APP_FILE"); | ||||
168 | if ((!appDataFile
| ||||
169 | if (argc == 2) { | ||||
170 | Output("Incorrect number of arguments passed to -app"); | ||||
171 | return 255; | ||||
172 | } | ||||
173 | appDataFile = argv[2]; | ||||
174 | |||||
175 | char appEnv[MAXPATHLEN4096]; | ||||
176 | SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]); | ||||
177 | if (putenv(strdup(appEnv))) { | ||||
178 | Output("Couldn't set %s.\n", appEnv); | ||||
179 | return 255; | ||||
180 | } | ||||
181 | argv[2] = argv[0]; | ||||
| |||||
182 | argv += 2; | ||||
183 | argc -= 2; | ||||
184 | } else if (argc > 1 && IsArg(argv[1], "xpcshell")) { | ||||
185 | for (int i = 1; i < argc; i++) { | ||||
186 | argv[i] = argv[i + 1]; | ||||
187 | } | ||||
188 | |||||
189 | XREShellData shellData; | ||||
190 | #if defined(XP_WIN) && defined(MOZ_SANDBOX1) | ||||
191 | shellData.sandboxBrokerServices = | ||||
192 | sandboxing::GetInitializedBrokerServices(); | ||||
193 | #endif | ||||
194 | |||||
195 | #ifdef LIBFUZZER | ||||
196 | shellData.fuzzerDriver = fuzzer::FuzzerDriver; | ||||
197 | #endif | ||||
198 | #ifdef AFLFUZZ | ||||
199 | shellData.fuzzerDriver = afl_interface_raw; | ||||
200 | #endif | ||||
201 | |||||
202 | return gBootstrap->XRE_XPCShellMain(--argc, argv, envp, &shellData); | ||||
203 | } | ||||
204 | |||||
205 | BootstrapConfig config; | ||||
206 | |||||
207 | if (appDataFile && *appDataFile) { | ||||
208 | config.appData = nullptr; | ||||
209 | config.appDataPath = appDataFile; | ||||
210 | } else { | ||||
211 | // no -app flag so we use the compiled-in app data | ||||
212 | config.appData = &sAppData; | ||||
213 | config.appDataPath = kDesktopFolder"browser"; | ||||
214 | } | ||||
215 | |||||
216 | #if defined(XP_WIN) && defined(MOZ_SANDBOX1) | ||||
217 | sandbox::BrokerServices* brokerServices = | ||||
218 | sandboxing::GetInitializedBrokerServices(); | ||||
219 | if (!brokerServices) { | ||||
220 | Output("Couldn't initialize the broker services.\n"); | ||||
221 | return 255; | ||||
222 | } | ||||
223 | config.sandboxBrokerServices = brokerServices; | ||||
224 | #endif | ||||
225 | |||||
226 | #ifdef LIBFUZZER | ||||
227 | if (getenv("FUZZER")) | ||||
228 | gBootstrap->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver); | ||||
229 | #endif | ||||
230 | |||||
231 | EnsureBrowserCommandlineSafe(argc, argv); | ||||
232 | |||||
233 | return gBootstrap->XRE_main(argc, argv, config); | ||||
234 | } | ||||
235 | |||||
236 | static nsresult InitXPCOMGlue(LibLoadingStrategy aLibLoadingStrategy) { | ||||
237 | if (gBootstrap) { | ||||
238 | return NS_OK; | ||||
239 | } | ||||
240 | |||||
241 | UniqueFreePtr<char> exePath = BinaryPath::Get(); | ||||
242 | if (!exePath) { | ||||
243 | Output("Couldn't find the application directory.\n"); | ||||
244 | return NS_ERROR_FAILURE; | ||||
245 | } | ||||
246 | |||||
247 | auto bootstrapResult = | ||||
248 | mozilla::GetBootstrap(exePath.get(), aLibLoadingStrategy); | ||||
249 | if (bootstrapResult.isErr()) { | ||||
250 | Output("Couldn't load XPCOM.\n"); | ||||
251 | return NS_ERROR_FAILURE; | ||||
252 | } | ||||
253 | |||||
254 | gBootstrap = bootstrapResult.unwrap(); | ||||
255 | |||||
256 | // This will set this thread as the main thread. | ||||
257 | gBootstrap->NS_LogInit(); | ||||
258 | |||||
259 | return NS_OK; | ||||
260 | } | ||||
261 | |||||
262 | #ifdef HAS_DLL_BLOCKLIST | ||||
263 | // NB: This must be extern, as this value is checked elsewhere | ||||
264 | uint32_t gBlocklistInitFlags = eDllBlocklistInitFlagDefault; | ||||
265 | #endif | ||||
266 | |||||
267 | #if defined(XP_UNIX1) | ||||
268 | static void ReserveDefaultFileDescriptors() { | ||||
269 | // Reserve the lower positions of the file descriptors to make sure | ||||
270 | // we don't reuse stdin/stdout/stderr in case they we closed | ||||
271 | // before launch. | ||||
272 | // Otherwise code explicitly writing to fd 1 or 2 might accidentally | ||||
273 | // write to something else, like in bug 1820896 where FD 1 is | ||||
274 | // reused for the X server display connection. | ||||
275 | int fd = open("/dev/null", O_RDONLY00); | ||||
276 | for (int i = 0; i < 2; i++) { | ||||
277 | mozilla::Unused << dup(fd); | ||||
278 | } | ||||
279 | } | ||||
280 | #endif | ||||
281 | |||||
282 | int main(int argc, char* argv[], char* envp[]) { | ||||
283 | #if defined(XP_UNIX1) | ||||
284 | ReserveDefaultFileDescriptors(); | ||||
285 | #endif | ||||
286 | |||||
287 | #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC | ||||
288 | if (argc > 1 && IsArg(argv[1], "contentproc")) { | ||||
| |||||
289 | // Set the process type and gecko child id. | ||||
290 | SetGeckoProcessType(argv[--argc]); | ||||
291 | SetGeckoChildID(argv[--argc]); | ||||
292 | |||||
293 | # if defined(MOZ_ENABLE_FORKSERVER1) | ||||
294 | if (GetGeckoProcessType() == GeckoProcessType_ForkServer) { | ||||
295 | nsresult rv = InitXPCOMGlue(LibLoadingStrategy::NoReadAhead); | ||||
296 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | ||||
297 | return 255; | ||||
298 | } | ||||
299 | |||||
300 | // Run a fork server in this process, single thread. When it returns, it | ||||
301 | // means the fork server have been stopped or a new child process is | ||||
302 | // created. | ||||
303 | // | ||||
304 | // For the latter case, XRE_ForkServer() will return false, running in a | ||||
305 | // child process just forked from the fork server process. argc & argv | ||||
306 | // will be updated with the values passing from the chrome process, as | ||||
307 | // will GeckoProcessType and GeckoChildID. With the new values, this | ||||
308 | // function continues the reset of the code acting as a child process. | ||||
309 | if (gBootstrap->XRE_ForkServer(&argc, &argv)) { | ||||
310 | // Return from the fork server in the fork server process. | ||||
311 | // Stop the fork server. | ||||
312 | // InitXPCOMGlue calls NS_LogInit, so we need to balance it here. | ||||
313 | gBootstrap->NS_LogTerm(); | ||||
314 | return 0; | ||||
315 | } | ||||
316 | } | ||||
317 | # endif | ||||
318 | } | ||||
319 | #endif | ||||
320 | |||||
321 | mozilla::TimeStamp start = mozilla::TimeStamp::Now(); | ||||
322 | |||||
323 | AUTO_BASE_PROFILER_INIT::mozilla::baseprofiler::AutoProfilerInit raiiObject323; | ||||
324 | AUTO_BASE_PROFILER_LABEL("nsBrowserApp main", OTHER)::mozilla::baseprofiler::AutoProfilerLabel raiiObject324( "nsBrowserApp main" , nullptr, ::mozilla::baseprofiler::ProfilingCategoryPair::OTHER ); | ||||
325 | |||||
326 | // Register an external module to report on otherwise uncatchable exceptions. | ||||
327 | // Note that in child processes this must be called after Gecko process type | ||||
328 | // has been set. | ||||
329 | CrashReporter::RegisterRuntimeExceptionModule(); | ||||
330 | |||||
331 | // Make sure we unregister the runtime exception module before returning. | ||||
332 | auto unregisterRuntimeExceptionModule = | ||||
333 | MakeScopeExit([] { CrashReporter::UnregisterRuntimeExceptionModule(); }); | ||||
334 | |||||
335 | #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC | ||||
336 | // We are launching as a content process, delegate to the appropriate | ||||
337 | // main | ||||
338 | if (GetGeckoProcessType() != GeckoProcessType_Default) { | ||||
339 | # if defined(XP_WIN) && defined(MOZ_SANDBOX1) | ||||
340 | // We need to set whether our process is supposed to have win32k locked down | ||||
341 | // from the command line setting before DllBlocklist_Initialize, | ||||
342 | // GetInitializedTargetServices and WindowsDpiInitialization. | ||||
343 | Maybe<bool> win32kLockedDown = | ||||
344 | mozilla::geckoargs::sWin32kLockedDown.Get(argc, argv); | ||||
345 | if (win32kLockedDown.isSome() && *win32kLockedDown) { | ||||
346 | mozilla::SetWin32kLockedDownInPolicy(); | ||||
347 | } | ||||
348 | # endif | ||||
349 | |||||
350 | # ifdef HAS_DLL_BLOCKLIST | ||||
351 | uint32_t initFlags = | ||||
352 | gBlocklistInitFlags | eDllBlocklistInitFlagIsChildProcess; | ||||
353 | SetDllBlocklistProcessTypeFlags(initFlags, GetGeckoProcessType()); | ||||
354 | DllBlocklist_Initialize(initFlags); | ||||
355 | # endif // HAS_DLL_BLOCKLIST | ||||
356 | |||||
357 | # if defined(XP_WIN) && defined(MOZ_SANDBOX1) | ||||
358 | // We need to initialize the sandbox TargetServices before InitXPCOMGlue | ||||
359 | // because we might need the sandbox broker to give access to some files. | ||||
360 | if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) { | ||||
361 | Output("Failed to initialize the sandbox target services."); | ||||
362 | return 255; | ||||
363 | } | ||||
364 | # endif | ||||
365 | # if defined(XP_WIN) | ||||
366 | // Ideally, we would be able to set our DPI awareness in | ||||
367 | // firefox.exe.manifest Unfortunately, that would cause Win32k calls when | ||||
368 | // user32.dll gets loaded, which would be incompatible with Win32k Lockdown | ||||
369 | // | ||||
370 | // MSDN says that it's allowed-but-not-recommended to initialize DPI | ||||
371 | // programatically, as long as it's done before any HWNDs are created. | ||||
372 | // Thus, we do it almost as soon as we possibly can | ||||
373 | { | ||||
374 | auto result = mozilla::WindowsDpiInitialization(); | ||||
375 | (void)result; // Ignore errors since some tools block DPI calls | ||||
376 | } | ||||
377 | # endif | ||||
378 | |||||
379 | nsresult rv = InitXPCOMGlue(LibLoadingStrategy::NoReadAhead); | ||||
380 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | ||||
381 | return 255; | ||||
382 | } | ||||
383 | |||||
384 | XREChildData childData; | ||||
385 | |||||
386 | # if defined(XP_WIN) && defined(MOZ_SANDBOX1) | ||||
387 | if (IsSandboxedProcess()) { | ||||
388 | childData.sandboxTargetServices = | ||||
389 | mozilla::sandboxing::GetInitializedTargetServices(); | ||||
390 | if (!childData.sandboxTargetServices) { | ||||
391 | return 1; | ||||
392 | } | ||||
393 | |||||
394 | childData.ProvideLogFunction = mozilla::sandboxing::ProvideLogFunction; | ||||
395 | } | ||||
396 | |||||
397 | if (GetGeckoProcessType() == GeckoProcessType_RemoteSandboxBroker) { | ||||
398 | childData.sandboxBrokerServices = | ||||
399 | mozilla::sandboxing::GetInitializedBrokerServices(); | ||||
400 | } | ||||
401 | # endif | ||||
402 | |||||
403 | rv = gBootstrap->XRE_InitChildProcess(argc, argv, &childData); | ||||
404 | |||||
405 | # if defined(DEBUG1) && defined(HAS_DLL_BLOCKLIST) | ||||
406 | DllBlocklist_Shutdown(); | ||||
407 | # endif | ||||
408 | |||||
409 | // InitXPCOMGlue calls NS_LogInit, so we need to balance it here. | ||||
410 | gBootstrap->NS_LogTerm(); | ||||
411 | |||||
412 | return NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) ? 1 : 0; | ||||
413 | } | ||||
414 | #endif | ||||
415 | |||||
416 | #ifdef HAS_DLL_BLOCKLIST | ||||
417 | DllBlocklist_Initialize(gBlocklistInitFlags); | ||||
418 | #endif | ||||
419 | |||||
420 | // We will likely only ever support this as a command line argument on Windows | ||||
421 | // and OSX, so we're ifdefing here just to not create any expectations. | ||||
422 | #if defined(XP_WIN) || defined(XP_MACOSX) | ||||
423 | if (argc > 1 && IsArg(argv[1], "silentmode")) { | ||||
424 | ::putenv(const_cast<char*>("MOZ_APP_SILENT_START=1")); | ||||
425 | # if defined(XP_WIN) | ||||
426 | // On windows We also want to set a separate variable, which we want to | ||||
427 | // persist across restarts, which will let us keep the process alive | ||||
428 | // even if the last window is closed. | ||||
429 | ::putenv(const_cast<char*>("MOZ_APP_ALLOW_WINDOWLESS=1")); | ||||
430 | # endif | ||||
431 | # if defined(XP_MACOSX) | ||||
432 | ::putenv(const_cast<char*>("MOZ_APP_NO_DOCK=1")); | ||||
433 | # endif | ||||
434 | } | ||||
435 | #endif | ||||
436 | |||||
437 | #if defined(XP_WIN) | ||||
438 | |||||
439 | // Ideally, we would be able to set our DPI awareness in firefox.exe.manifest | ||||
440 | // Unfortunately, that would cause Win32k calls when user32.dll gets loaded, | ||||
441 | // which would be incompatible with Win32k Lockdown | ||||
442 | // | ||||
443 | // MSDN says that it's allowed-but-not-recommended to initialize DPI | ||||
444 | // programatically, as long as it's done before any HWNDs are created. | ||||
445 | // Thus, we do it almost as soon as we possibly can | ||||
446 | { | ||||
447 | auto result = mozilla::WindowsDpiInitialization(); | ||||
448 | (void)result; // Ignore errors since some tools block DPI calls | ||||
449 | } | ||||
450 | |||||
451 | // Once the browser process hits the main function, we no longer need | ||||
452 | // a writable section handle because all dependent modules have been | ||||
453 | // loaded. | ||||
454 | mozilla::freestanding::gSharedSection.ConvertToReadOnly(); | ||||
455 | |||||
456 | mozilla::CreateAndStorePreXULSkeletonUI(GetModuleHandle(nullptr), argc, argv); | ||||
457 | #endif | ||||
458 | |||||
459 | nsresult rv = InitXPCOMGlue(LibLoadingStrategy::ReadAhead); | ||||
460 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | ||||
461 | return 255; | ||||
462 | } | ||||
463 | |||||
464 | gBootstrap->XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start); | ||||
465 | |||||
466 | #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC | ||||
467 | gBootstrap->XRE_EnableSameExecutableForContentProc(); | ||||
468 | #endif | ||||
469 | |||||
470 | int result = do_main(argc, argv, envp); | ||||
471 | |||||
472 | #if defined(XP_WIN) | ||||
473 | CleanupProcessRuntime(); | ||||
474 | #endif | ||||
475 | |||||
476 | gBootstrap->NS_LogTerm(); | ||||
477 | |||||
478 | #if defined(DEBUG1) && defined(HAS_DLL_BLOCKLIST) | ||||
479 | DllBlocklist_Shutdown(); | ||||
480 | #endif | ||||
481 | |||||
482 | #ifdef XP_MACOSX | ||||
483 | // Allow writes again. While we would like to catch writes from static | ||||
484 | // destructors to allow early exits to use _exit, we know that there is | ||||
485 | // at least one such write that we don't control (see bug 826029). For | ||||
486 | // now we enable writes again and early exits will have to use exit instead | ||||
487 | // of _exit. | ||||
488 | gBootstrap->XRE_StopLateWriteChecks(); | ||||
489 | #endif | ||||
490 | |||||
491 | gBootstrap.reset(); | ||||
492 | |||||
493 | return result; | ||||
494 | } |